Skip to content

Commit f2ed1ab

Browse files
committed
Auto merge of #1218 - RalfJung:panic, r=RalfJung
properly panic in panic_if_uninhabited and align_offset shims
2 parents 96d080a + 8394456 commit f2ed1ab

File tree

7 files changed

+97
-62
lines changed

7 files changed

+97
-62
lines changed

src/shims/intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
448448
let ty = substs.type_at(0);
449449
let layout = this.layout_of(ty)?;
450450
if layout.abi.is_uninhabited() {
451-
// FIXME: This should throw a panic in the interpreted program instead.
452-
throw_unsup_format!("Trying to instantiate uninhabited type {}", ty)
451+
// Return here because we paniced instead of returning normally from the intrinsic.
452+
return this.start_panic(&format!("Attempted to instantiate uninhabited type {}", ty), unwind);
453453
}
454454
}
455455

src/shims/mod.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2424

2525
// There are some more lang items we want to hook that CTFE does not hook (yet).
2626
if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
27-
let (dest, ret) = ret.unwrap();
28-
let n = this
29-
.align_offset(args[0], args[1])?
30-
.unwrap_or_else(|| this.truncate(u128::MAX, dest.layout));
31-
this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
32-
this.go_to_block(ret);
27+
this.align_offset(args[0], args[1], ret, unwind)?;
3328
return Ok(None);
3429
}
3530

@@ -52,35 +47,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5247
&mut self,
5348
ptr_op: OpTy<'tcx, Tag>,
5449
align_op: OpTy<'tcx, Tag>,
55-
) -> InterpResult<'tcx, Option<u128>> {
50+
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
51+
unwind: Option<mir::BasicBlock>,
52+
) -> InterpResult<'tcx> {
5653
let this = self.eval_context_mut();
54+
let (dest, ret) = ret.unwrap();
5755

5856
let req_align = this
5957
.force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?
6058
as usize;
6159

62-
// FIXME: This should actually panic in the interpreted program
60+
// Stop if the alignment is not a power of two.
6361
if !req_align.is_power_of_two() {
64-
throw_unsup_format!("Required alignment should always be a power of two")
62+
return this.start_panic("align_offset: align is not a power-of-two", unwind);
6563
}
6664

6765
let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?;
6866

67+
// Default: no result.
68+
let mut result = this.truncate(u128::MAX, dest.layout);
6969
if let Ok(ptr) = this.force_ptr(ptr_scalar) {
70+
// Only do anything if we can identify the allocation this goes to.
7071
let cur_align =
7172
this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes()
7273
as usize;
7374
if cur_align >= req_align {
74-
// if the allocation alignment is at least the required alignment we use the
75+
// If the allocation alignment is at least the required alignment we use the
7576
// libcore implementation
76-
return Ok(Some(
77-
(this.force_bits(ptr_scalar, this.pointer_size())? as *const i8)
78-
.align_offset(req_align) as u128,
79-
));
77+
result = (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8).align_offset(req_align) as u128;
8078
}
8179
}
82-
// If the allocation alignment is smaller than then required alignment or the pointer was
83-
// actually an integer, we return `None`
84-
Ok(None)
80+
81+
// Return result, and jump to caller.
82+
this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?;
83+
this.go_to_block(ret);
84+
Ok(())
8585
}
8686
}

src/shims/panic.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
152152
Ok(res)
153153
}
154154

155+
/// Starta a panic in the interpreter with the given message as payload.
156+
fn start_panic(
157+
&mut self,
158+
msg: &str,
159+
unwind: Option<mir::BasicBlock>,
160+
) -> InterpResult<'tcx> {
161+
let this = self.eval_context_mut();
162+
163+
// First arg: message.
164+
let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into());
165+
166+
// Call the lang item.
167+
let panic = this.tcx.lang_items().panic_fn().unwrap();
168+
let panic = ty::Instance::mono(this.tcx.tcx, panic);
169+
this.call_function(
170+
panic,
171+
&[msg.to_ref()],
172+
None,
173+
StackPopCleanup::Goto { ret: None, unwind },
174+
)
175+
}
176+
155177
fn assert_panic(
156178
&mut self,
157179
span: Span,
@@ -184,20 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
184206
}
185207
_ => {
186208
// Forward everything else to `panic` lang item.
187-
188-
// First arg: Message.
189-
let msg = msg.description();
190-
let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into());
191-
192-
// Call the lang item.
193-
let panic = this.tcx.lang_items().panic_fn().unwrap();
194-
let panic = ty::Instance::mono(this.tcx.tcx, panic);
195-
this.call_function(
196-
panic,
197-
&[msg.to_ref()],
198-
None,
199-
StackPopCleanup::Goto { ret: None, unwind },
200-
)?;
209+
this.start_panic(msg.description(), unwind)?;
201210
}
202211
}
203212
Ok(())

tests/run-pass/panic/catch_panic.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// ignore-windows: Unwind panicking does not currently work on Windows
2-
// normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC"
2+
// normalize-stderr-test "[^ ]*libcore/(macros|mem)/mod.rs[0-9:]*" -> "$$LOC"
33
#![feature(never_type)]
44
#![allow(unconditional_panic)]
55
use std::panic::{catch_unwind, AssertUnwindSafe};
@@ -47,32 +47,49 @@ fn main() {
4747
}));
4848

4949
// Std panics
50-
test(|_old_val| std::panic!("Hello from panic: std"));
51-
test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val)));
52-
test(|old_val| std::panic!("Hello from panic: {:?}", old_val));
53-
test(|_old_val| std::panic!(1337));
50+
test(None, |_old_val| std::panic!("Hello from panic: std"));
51+
test(None, |old_val| std::panic!(format!("Hello from panic: {:?}", old_val)));
52+
test(None, |old_val| std::panic!("Hello from panic: {:?}", old_val));
53+
test(None, |_old_val| std::panic!(1337));
5454

5555
// Core panics
56-
test(|_old_val| core::panic!("Hello from panic: core"));
57-
test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val)));
58-
test(|old_val| core::panic!("Hello from panic: {:?}", old_val));
59-
60-
// Built-in panics
61-
test(|_old_val| { let _val = [0, 1, 2][4]; loop {} });
62-
test(|_old_val| { let _val = 1/0; loop {} });
56+
test(None, |_old_val| core::panic!("Hello from panic: core"));
57+
test(None, |old_val| core::panic!(&format!("Hello from panic: {:?}", old_val)));
58+
test(None, |old_val| core::panic!("Hello from panic: {:?}", old_val));
59+
60+
// Built-in panics; also make sure the message is right.
61+
test(
62+
Some("index out of bounds: the len is 3 but the index is 4"),
63+
|_old_val| { let _val = [0, 1, 2][4]; loop {} },
64+
);
65+
test(
66+
Some("attempt to divide by zero"),
67+
|_old_val| { let _val = 1/0; loop {} },
68+
);
69+
70+
// libcore panics from shims.
71+
#[allow(deprecated, invalid_value)]
72+
test(
73+
Some("Attempted to instantiate uninhabited type !"),
74+
|_old_val| unsafe { std::mem::uninitialized::<!>() },
75+
);
76+
test(
77+
Some("align_offset: align is not a power-of-two"),
78+
|_old_val| { (0usize as *const u8).align_offset(3); loop {} },
79+
);
6380

6481
// Assertion and debug assertion
65-
test(|_old_val| { assert!(false); loop {} });
66-
test(|_old_val| { debug_assert!(false); loop {} });
67-
test(|_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd
82+
test(None, |_old_val| { assert!(false); loop {} });
83+
test(None, |_old_val| { debug_assert!(false); loop {} });
84+
test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd
6885

6986
// Cleanup: reset to default hook.
7087
drop(std::panic::take_hook());
7188

7289
eprintln!("Success!"); // Make sure we get this in stderr
7390
}
7491

75-
fn test(do_panic: impl FnOnce(usize) -> !) {
92+
fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) {
7693
// Reset test flags.
7794
DROPPED.with(|c| c.set(false));
7895
HOOK_CALLED.with(|c| c.set(false));
@@ -84,16 +101,21 @@ fn test(do_panic: impl FnOnce(usize) -> !) {
84101
})).expect_err("do_panic() did not panic!");
85102

86103
// See if we can extract the panic message.
87-
if let Some(s) = res.downcast_ref::<String>() {
104+
let msg = if let Some(s) = res.downcast_ref::<String>() {
88105
eprintln!("Caught panic message (String): {}", s);
106+
Some(s.as_str())
89107
} else if let Some(s) = res.downcast_ref::<&str>() {
90108
eprintln!("Caught panic message (&str): {}", s);
109+
Some(*s)
91110
} else {
92111
eprintln!("Failed get caught panic message.");
112+
None
113+
};
114+
if let Some(expect_msg) = expect_msg {
115+
assert_eq!(expect_msg, msg.unwrap());
93116
}
94117

95118
// Test flags.
96119
assert!(DROPPED.with(|c| c.get()));
97120
assert!(HOOK_CALLED.with(|c| c.get()));
98121
}
99-

tests/run-pass/panic/catch_panic.stderr

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1-
thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:21
1+
thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:27
22
Caught panic message (&str): Hello from panic: std
3-
thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:20
3+
thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:26
44
Caught panic message (String): Hello from panic: 1
5-
thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:20
5+
thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:26
66
Caught panic message (String): Hello from panic: 2
7-
thread 'main' panicked at 'Box<Any>', $DIR/catch_panic.rs:53:21
7+
thread 'main' panicked at 'Box<Any>', $DIR/catch_panic.rs:53:27
88
Failed get caught panic message.
9-
thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:21
9+
thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:27
1010
Caught panic message (String): Hello from panic: core
11-
thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:20
11+
thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:26
1212
Caught panic message (String): Hello from panic: 5
13-
thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:20
13+
thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:26
1414
Caught panic message (String): Hello from panic: 6
15-
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:61:34
15+
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:63:33
1616
Caught panic message (String): index out of bounds: the len is 3 but the index is 4
17-
thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34
17+
thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33
1818
Caught panic message (String): attempt to divide by zero
19-
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23
19+
thread 'main' panicked at 'Attempted to instantiate uninhabited type !', $LOC
20+
Caught panic message (String): Attempted to instantiate uninhabited type !
21+
thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC
22+
Caught panic message (String): align_offset: align is not a power-of-two
23+
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:82:29
2024
Caught panic message (&str): assertion failed: false
21-
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23
25+
thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:83:29
2226
Caught panic message (&str): assertion failed: false
2327
thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC
2428
Caught panic message (String): attempt to copy from unaligned or null pointer

0 commit comments

Comments
 (0)