properly panic in panic_if_uninhabited and align_offset shims
This commit is contained in:
parent
96d080a542
commit
8394456247
7 changed files with 96 additions and 61 deletions
|
|
@ -448,8 +448,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let ty = substs.type_at(0);
|
||||
let layout = this.layout_of(ty)?;
|
||||
if layout.abi.is_uninhabited() {
|
||||
// FIXME: This should throw a panic in the interpreted program instead.
|
||||
throw_unsup_format!("Trying to instantiate uninhabited type {}", ty)
|
||||
// Return here because we paniced instead of returning normally from the intrinsic.
|
||||
return this.start_panic(&format!("Attempted to instantiate uninhabited type {}", ty), unwind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
// There are some more lang items we want to hook that CTFE does not hook (yet).
|
||||
if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
|
||||
let (dest, ret) = ret.unwrap();
|
||||
let n = this
|
||||
.align_offset(args[0], args[1])?
|
||||
.unwrap_or_else(|| this.truncate(u128::MAX, dest.layout));
|
||||
this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
|
||||
this.go_to_block(ret);
|
||||
this.align_offset(args[0], args[1], ret, unwind)?;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
|
@ -52,35 +47,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
&mut self,
|
||||
ptr_op: OpTy<'tcx, Tag>,
|
||||
align_op: OpTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, Option<u128>> {
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
unwind: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
let (dest, ret) = ret.unwrap();
|
||||
|
||||
let req_align = this
|
||||
.force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?
|
||||
as usize;
|
||||
|
||||
// FIXME: This should actually panic in the interpreted program
|
||||
// Stop if the alignment is not a power of two.
|
||||
if !req_align.is_power_of_two() {
|
||||
throw_unsup_format!("Required alignment should always be a power of two")
|
||||
return this.start_panic("align_offset: align is not a power-of-two", unwind);
|
||||
}
|
||||
|
||||
let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?;
|
||||
|
||||
// Default: no result.
|
||||
let mut result = this.truncate(u128::MAX, dest.layout);
|
||||
if let Ok(ptr) = this.force_ptr(ptr_scalar) {
|
||||
// Only do anything if we can identify the allocation this goes to.
|
||||
let cur_align =
|
||||
this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes()
|
||||
as usize;
|
||||
if cur_align >= req_align {
|
||||
// if the allocation alignment is at least the required alignment we use the
|
||||
// If the allocation alignment is at least the required alignment we use the
|
||||
// libcore implementation
|
||||
return Ok(Some(
|
||||
(this.force_bits(ptr_scalar, this.pointer_size())? as *const i8)
|
||||
.align_offset(req_align) as u128,
|
||||
));
|
||||
result = (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8).align_offset(req_align) as u128;
|
||||
}
|
||||
}
|
||||
// If the allocation alignment is smaller than then required alignment or the pointer was
|
||||
// actually an integer, we return `None`
|
||||
Ok(None)
|
||||
|
||||
// Return result, and jump to caller.
|
||||
this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?;
|
||||
this.go_to_block(ret);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
Ok(res)
|
||||
}
|
||||
|
||||
/// Starta a panic in the interpreter with the given message as payload.
|
||||
fn start_panic(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
unwind: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// First arg: message.
|
||||
let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into());
|
||||
|
||||
// Call the lang item.
|
||||
let panic = this.tcx.lang_items().panic_fn().unwrap();
|
||||
let panic = ty::Instance::mono(this.tcx.tcx, panic);
|
||||
this.call_function(
|
||||
panic,
|
||||
&[msg.to_ref()],
|
||||
None,
|
||||
StackPopCleanup::Goto { ret: None, unwind },
|
||||
)
|
||||
}
|
||||
|
||||
fn assert_panic(
|
||||
&mut self,
|
||||
span: Span,
|
||||
|
|
@ -184,20 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
_ => {
|
||||
// Forward everything else to `panic` lang item.
|
||||
|
||||
// First arg: Message.
|
||||
let msg = msg.description();
|
||||
let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into());
|
||||
|
||||
// Call the lang item.
|
||||
let panic = this.tcx.lang_items().panic_fn().unwrap();
|
||||
let panic = ty::Instance::mono(this.tcx.tcx, panic);
|
||||
this.call_function(
|
||||
panic,
|
||||
&[msg.to_ref()],
|
||||
None,
|
||||
StackPopCleanup::Goto { ret: None, unwind },
|
||||
)?;
|
||||
this.start_panic(msg.description(), unwind)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// ignore-windows: Unwind panicking does not currently work on Windows
|
||||
// normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC"
|
||||
// normalize-stderr-test "[^ ]*libcore/(macros|mem)/mod.rs[0-9:]*" -> "$$LOC"
|
||||
#![feature(never_type)]
|
||||
#![allow(unconditional_panic)]
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
|
|
@ -47,24 +47,41 @@ fn main() {
|
|||
}));
|
||||
|
||||
// Std panics
|
||||
test(|_old_val| std::panic!("Hello from panic: std"));
|
||||
test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val)));
|
||||
test(|old_val| std::panic!("Hello from panic: {:?}", old_val));
|
||||
test(|_old_val| std::panic!(1337));
|
||||
test(None, |_old_val| std::panic!("Hello from panic: std"));
|
||||
test(None, |old_val| std::panic!(format!("Hello from panic: {:?}", old_val)));
|
||||
test(None, |old_val| std::panic!("Hello from panic: {:?}", old_val));
|
||||
test(None, |_old_val| std::panic!(1337));
|
||||
|
||||
// Core panics
|
||||
test(|_old_val| core::panic!("Hello from panic: core"));
|
||||
test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val)));
|
||||
test(|old_val| core::panic!("Hello from panic: {:?}", old_val));
|
||||
test(None, |_old_val| core::panic!("Hello from panic: core"));
|
||||
test(None, |old_val| core::panic!(&format!("Hello from panic: {:?}", old_val)));
|
||||
test(None, |old_val| core::panic!("Hello from panic: {:?}", old_val));
|
||||
|
||||
// Built-in panics
|
||||
test(|_old_val| { let _val = [0, 1, 2][4]; loop {} });
|
||||
test(|_old_val| { let _val = 1/0; loop {} });
|
||||
// Built-in panics; also make sure the message is right.
|
||||
test(
|
||||
Some("index out of bounds: the len is 3 but the index is 4"),
|
||||
|_old_val| { let _val = [0, 1, 2][4]; loop {} },
|
||||
);
|
||||
test(
|
||||
Some("attempt to divide by zero"),
|
||||
|_old_val| { let _val = 1/0; loop {} },
|
||||
);
|
||||
|
||||
// libcore panics from shims.
|
||||
#[allow(deprecated, invalid_value)]
|
||||
test(
|
||||
Some("Attempted to instantiate uninhabited type !"),
|
||||
|_old_val| unsafe { std::mem::uninitialized::<!>() },
|
||||
);
|
||||
test(
|
||||
Some("align_offset: align is not a power-of-two"),
|
||||
|_old_val| { (0usize as *const u8).align_offset(3); loop {} },
|
||||
);
|
||||
|
||||
// Assertion and debug assertion
|
||||
test(|_old_val| { assert!(false); loop {} });
|
||||
test(|_old_val| { debug_assert!(false); loop {} });
|
||||
test(|_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd
|
||||
test(None, |_old_val| { assert!(false); loop {} });
|
||||
test(None, |_old_val| { debug_assert!(false); loop {} });
|
||||
test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd
|
||||
|
||||
// Cleanup: reset to default hook.
|
||||
drop(std::panic::take_hook());
|
||||
|
|
@ -72,7 +89,7 @@ fn main() {
|
|||
eprintln!("Success!"); // Make sure we get this in stderr
|
||||
}
|
||||
|
||||
fn test(do_panic: impl FnOnce(usize) -> !) {
|
||||
fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) {
|
||||
// Reset test flags.
|
||||
DROPPED.with(|c| c.set(false));
|
||||
HOOK_CALLED.with(|c| c.set(false));
|
||||
|
|
@ -84,16 +101,21 @@ fn test(do_panic: impl FnOnce(usize) -> !) {
|
|||
})).expect_err("do_panic() did not panic!");
|
||||
|
||||
// See if we can extract the panic message.
|
||||
if let Some(s) = res.downcast_ref::<String>() {
|
||||
let msg = if let Some(s) = res.downcast_ref::<String>() {
|
||||
eprintln!("Caught panic message (String): {}", s);
|
||||
Some(s.as_str())
|
||||
} else if let Some(s) = res.downcast_ref::<&str>() {
|
||||
eprintln!("Caught panic message (&str): {}", s);
|
||||
Some(*s)
|
||||
} else {
|
||||
eprintln!("Failed get caught panic message.");
|
||||
None
|
||||
};
|
||||
if let Some(expect_msg) = expect_msg {
|
||||
assert_eq!(expect_msg, msg.unwrap());
|
||||
}
|
||||
|
||||
// Test flags.
|
||||
assert!(DROPPED.with(|c| c.get()));
|
||||
assert!(HOOK_CALLED.with(|c| c.get()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,28 @@
|
|||
thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:21
|
||||
thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:27
|
||||
Caught panic message (&str): Hello from panic: std
|
||||
thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:20
|
||||
thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:26
|
||||
Caught panic message (String): Hello from panic: 1
|
||||
thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:20
|
||||
thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:26
|
||||
Caught panic message (String): Hello from panic: 2
|
||||
thread 'main' panicked at 'Box<Any>', $DIR/catch_panic.rs:53:21
|
||||
thread 'main' panicked at 'Box<Any>', $DIR/catch_panic.rs:53:27
|
||||
Failed get caught panic message.
|
||||
thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:21
|
||||
thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:27
|
||||
Caught panic message (String): Hello from panic: core
|
||||
thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:20
|
||||
thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:26
|
||||
Caught panic message (String): Hello from panic: 5
|
||||
thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:20
|
||||
thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:26
|
||||
Caught panic message (String): Hello from panic: 6
|
||||
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:61:34
|
||||
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:63:33
|
||||
Caught panic message (String): index out of bounds: the len is 3 but the index is 4
|
||||
thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34
|
||||
thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33
|
||||
Caught panic message (String): attempt to divide by zero
|
||||
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23
|
||||
thread 'main' panicked at 'Attempted to instantiate uninhabited type !', $LOC
|
||||
Caught panic message (String): Attempted to instantiate uninhabited type !
|
||||
thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC
|
||||
Caught panic message (String): align_offset: align is not a power-of-two
|
||||
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:82:29
|
||||
Caught panic message (&str): assertion failed: false
|
||||
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23
|
||||
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:83:29
|
||||
Caught panic message (&str): assertion failed: false
|
||||
thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC
|
||||
Caught panic message (String): attempt to copy from unaligned or null pointer
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue