Skip to content

Commit 85ed056

Browse files
committed
Auto merge of #3319 - bjorn3:some_more_shims, r=RalfJung
Directly implement native exception raise methods in miri This implements the `_Unwind_RaiseException` function used on pretty much every unix system for starting unwinding. This allows removing the miri special case from libpanic_unwind for unix. Windows still needs `miri_start_unwind` as SEH unwinding isn't supported by miri. Unlike DWARF unwinding, SEH preserves all stack frames until right after the do_catch function has executed. Because of this panic_unwind stack allocates the exception object. Miri can't currently model unwinding without destroying stack frames and as such will report a use-after-free of the exception object.
2 parents a32423c + 5e41ff5 commit 85ed056

26 files changed

+168
-48
lines changed

Diff for: src/tools/miri/ci/ci.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ case $HOST_TARGET in
145145
TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
146146
# Partially supported targets (tier 2)
147147
BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization)
148-
UNIX="panic/panic concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
148+
UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
149149
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs
150150
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs
151151
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX pthread-sync

Diff for: src/tools/miri/src/intrinsics/atomic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
116116

117117
_ => return Ok(EmulateItemResult::NotSupported),
118118
}
119-
Ok(EmulateItemResult::NeedsJumping)
119+
Ok(EmulateItemResult::NeedsReturn)
120120
}
121121
}
122122

Diff for: src/tools/miri/src/intrinsics/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2626
args: &[OpTy<'tcx, Provenance>],
2727
dest: &MPlaceTy<'tcx, Provenance>,
2828
ret: Option<mir::BasicBlock>,
29-
_unwind: mir::UnwindAction,
29+
unwind: mir::UnwindAction,
3030
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
3131
let this = self.eval_context_mut();
3232

@@ -62,11 +62,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6262
args: instance.args,
6363
}))
6464
}
65-
EmulateItemResult::NeedsJumping => {
65+
EmulateItemResult::NeedsReturn => {
6666
trace!("{:?}", this.dump_place(&dest.clone().into()));
6767
this.return_to_block(ret)?;
6868
Ok(None)
6969
}
70+
EmulateItemResult::NeedsUnwind => {
71+
// Jump to the unwind block to begin unwinding.
72+
this.unwind_to_block(unwind)?;
73+
Ok(None)
74+
}
7075
EmulateItemResult::AlreadyJumped => Ok(None),
7176
}
7277
}
@@ -441,6 +446,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
441446
_ => return Ok(EmulateItemResult::NotSupported),
442447
}
443448

444-
Ok(EmulateItemResult::NeedsJumping)
449+
Ok(EmulateItemResult::NeedsReturn)
445450
}
446451
}

Diff for: src/tools/miri/src/intrinsics/simd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
746746

747747
_ => return Ok(EmulateItemResult::NotSupported),
748748
}
749-
Ok(EmulateItemResult::NeedsJumping)
749+
Ok(EmulateItemResult::NeedsReturn)
750750
}
751751

752752
fn fminmax_op(

Diff for: src/tools/miri/src/shims/alloc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8787
}
8888
AllocatorKind::Default => {
8989
default(this)?;
90-
Ok(EmulateItemResult::NeedsJumping)
90+
Ok(EmulateItemResult::NeedsReturn)
9191
}
9292
}
9393
}

Diff for: src/tools/miri/src/shims/foreign_items.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8282
}
8383

8484
// The rest either implements the logic, or falls back to `lookup_exported_symbol`.
85-
match this.emulate_foreign_item_inner(link_name, abi, args, dest, unwind)? {
86-
EmulateItemResult::NeedsJumping => {
85+
match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
86+
EmulateItemResult::NeedsReturn => {
8787
trace!("{:?}", this.dump_place(&dest.clone().into()));
8888
this.return_to_block(ret)?;
8989
}
90+
EmulateItemResult::NeedsUnwind => {
91+
// Jump to the unwind block to begin unwinding.
92+
this.unwind_to_block(unwind)?;
93+
}
9094
EmulateItemResult::AlreadyJumped => (),
9195
EmulateItemResult::NotSupported => {
9296
if let Some(body) = this.lookup_exported_symbol(link_name)? {
@@ -206,7 +210,6 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
206210
abi: Abi,
207211
args: &[OpTy<'tcx, Provenance>],
208212
dest: &MPlaceTy<'tcx, Provenance>,
209-
unwind: mir::UnwindAction,
210213
) -> InterpResult<'tcx, EmulateItemResult> {
211214
let this = self.eval_context_mut();
212215

@@ -218,7 +221,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
218221
// by the specified `.so` file; we should continue and check if it corresponds to
219222
// a provided shim.
220223
if this.call_native_fn(link_name, dest, args)? {
221-
return Ok(EmulateItemResult::NeedsJumping);
224+
return Ok(EmulateItemResult::NeedsReturn);
222225
}
223226
}
224227

@@ -263,9 +266,9 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
263266
match link_name.as_str() {
264267
// Miri-specific extern functions
265268
"miri_start_unwind" => {
266-
// `check_shim` happens inside `handle_miri_start_unwind`.
267-
this.handle_miri_start_unwind(abi, link_name, args, unwind)?;
268-
return Ok(EmulateItemResult::AlreadyJumped);
269+
let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
270+
this.handle_miri_start_unwind(payload)?;
271+
return Ok(EmulateItemResult::NeedsUnwind);
269272
}
270273
"miri_run_provenance_gc" => {
271274
let [] = this.check_shim(abi, Abi::Rust, link_name, args)?;
@@ -480,7 +483,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
480483
"__rust_alloc" => return this.emulate_allocator(default),
481484
"miri_alloc" => {
482485
default(this)?;
483-
return Ok(EmulateItemResult::NeedsJumping);
486+
return Ok(EmulateItemResult::NeedsReturn);
484487
}
485488
_ => unreachable!(),
486489
}
@@ -540,7 +543,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
540543
}
541544
"miri_dealloc" => {
542545
default(this)?;
543-
return Ok(EmulateItemResult::NeedsJumping);
546+
return Ok(EmulateItemResult::NeedsReturn);
544547
}
545548
_ => unreachable!(),
546549
}
@@ -961,6 +964,6 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
961964
};
962965
// We only fall through to here if we did *not* hit the `_` arm above,
963966
// i.e., if we actually emulated the function with one of the shims.
964-
Ok(EmulateItemResult::NeedsJumping)
967+
Ok(EmulateItemResult::NeedsReturn)
965968
}
966969
}

Diff for: src/tools/miri/src/shims/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ pub use unix::{DirTable, FdTable};
2222
/// What needs to be done after emulating an item (a shim or an intrinsic) is done.
2323
pub enum EmulateItemResult {
2424
/// The caller is expected to jump to the return block.
25-
NeedsJumping,
26-
/// Jumping has already been taken care of.
25+
NeedsReturn,
26+
/// The caller is expected to jump to the unwind block.
27+
NeedsUnwind,
28+
/// Jumping to the next block has already been taken care of.
2729
AlreadyJumped,
2830
/// The item is not supported.
2931
NotSupported,

Diff for: src/tools/miri/src/shims/panic.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
1414
use rustc_ast::Mutability;
1515
use rustc_middle::{mir, ty};
16-
use rustc_span::Symbol;
1716
use rustc_target::spec::abi::Abi;
1817
use rustc_target::spec::PanicStrategy;
1918

@@ -46,25 +45,15 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir,
4645
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4746
/// Handles the special `miri_start_unwind` intrinsic, which is called
4847
/// by libpanic_unwind to delegate the actual unwinding process to Miri.
49-
fn handle_miri_start_unwind(
50-
&mut self,
51-
abi: Abi,
52-
link_name: Symbol,
53-
args: &[OpTy<'tcx, Provenance>],
54-
unwind: mir::UnwindAction,
55-
) -> InterpResult<'tcx> {
48+
fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
5649
let this = self.eval_context_mut();
5750

5851
trace!("miri_start_unwind: {:?}", this.frame().instance);
5952

60-
// Get the raw pointer stored in arg[0] (the panic payload).
61-
let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
6253
let payload = this.read_scalar(payload)?;
6354
let thread = this.active_thread_mut();
6455
thread.panic_payloads.push(payload);
6556

66-
// Jump to the unwind block to begin unwinding.
67-
this.unwind_to_block(unwind)?;
6857
Ok(())
6958
}
7059

Diff for: src/tools/miri/src/shims/unix/android/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2727

2828
_ => return Ok(EmulateItemResult::NotSupported),
2929
}
30-
Ok(EmulateItemResult::NeedsJumping)
30+
Ok(EmulateItemResult::NeedsReturn)
3131
}
3232
}

Diff for: src/tools/miri/src/shims/unix/foreign_items.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
639639
this.gen_random(ptr, len)?;
640640
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
641641
}
642+
"_Unwind_RaiseException" => {
643+
// This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
644+
// It was originally specified as part of the Itanium C++ ABI:
645+
// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
646+
// On Linux it is
647+
// documented as part of the LSB:
648+
// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-raiseexception.html
649+
// Basically every other UNIX uses the exact same api though. Arm also references
650+
// back to the Itanium C++ ABI for the definition of `_Unwind_RaiseException` for
651+
// arm64:
652+
// https://github.com/ARM-software/abi-aa/blob/main/cppabi64/cppabi64.rst#toc-entry-35
653+
// For arm32 they did something custom, but similar enough that the same
654+
// `_Unwind_RaiseException` impl in miri should work:
655+
// https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
656+
if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos") {
657+
throw_unsup_format!(
658+
"`_Unwind_RaiseException` is not supported on {}",
659+
this.tcx.sess.target.os
660+
);
661+
}
662+
// This function looks and behaves excatly like miri_start_unwind.
663+
let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
664+
this.handle_miri_start_unwind(payload)?;
665+
return Ok(EmulateItemResult::NeedsUnwind);
666+
}
642667

643668
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
644669
// These shims are enabled only when the caller is in the standard library.
@@ -760,6 +785,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
760785
}
761786
};
762787

763-
Ok(EmulateItemResult::NeedsJumping)
788+
Ok(EmulateItemResult::NeedsReturn)
764789
}
765790
}

Diff for: src/tools/miri/src/shims/unix/freebsd/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8686

8787
_ => return Ok(EmulateItemResult::NotSupported),
8888
}
89-
Ok(EmulateItemResult::NeedsJumping)
89+
Ok(EmulateItemResult::NeedsReturn)
9090
}
9191
}

Diff for: src/tools/miri/src/shims/unix/linux/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
203203
_ => return Ok(EmulateItemResult::NotSupported),
204204
};
205205

206-
Ok(EmulateItemResult::NeedsJumping)
206+
Ok(EmulateItemResult::NeedsReturn)
207207
}
208208
}

Diff for: src/tools/miri/src/shims/unix/macos/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
177177
_ => return Ok(EmulateItemResult::NotSupported),
178178
};
179179

180-
Ok(EmulateItemResult::NeedsJumping)
180+
Ok(EmulateItemResult::NeedsReturn)
181181
}
182182
}

Diff for: src/tools/miri/src/shims/unix/solarish/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4545

4646
_ => return Ok(EmulateItemResult::NotSupported),
4747
}
48-
Ok(EmulateItemResult::NeedsJumping)
48+
Ok(EmulateItemResult::NeedsReturn)
4949
}
5050
}

Diff for: src/tools/miri/src/shims/wasi/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
3535

3636
_ => return Ok(EmulateItemResult::NotSupported),
3737
}
38-
Ok(EmulateItemResult::NeedsJumping)
38+
Ok(EmulateItemResult::NeedsReturn)
3939
}
4040
}

Diff for: src/tools/miri/src/shims/windows/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
762762
_ => return Ok(EmulateItemResult::NotSupported),
763763
}
764764

765-
Ok(EmulateItemResult::NeedsJumping)
765+
Ok(EmulateItemResult::NeedsReturn)
766766
}
767767
}

Diff for: src/tools/miri/src/shims/x86/aesni.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
127127
// with an external crate.
128128
_ => return Ok(EmulateItemResult::NotSupported),
129129
}
130-
Ok(EmulateItemResult::NeedsJumping)
130+
Ok(EmulateItemResult::NeedsReturn)
131131
}
132132
}
133133

Diff for: src/tools/miri/src/shims/x86/avx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
344344
}
345345
_ => return Ok(EmulateItemResult::NotSupported),
346346
}
347-
Ok(EmulateItemResult::NeedsJumping)
347+
Ok(EmulateItemResult::NeedsReturn)
348348
}
349349
}

Diff for: src/tools/miri/src/shims/x86/avx2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
440440
}
441441
_ => return Ok(EmulateItemResult::NotSupported),
442442
}
443-
Ok(EmulateItemResult::NeedsJumping)
443+
Ok(EmulateItemResult::NeedsReturn)
444444
}
445445
}

Diff for: src/tools/miri/src/shims/x86/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
144144

145145
_ => return Ok(EmulateItemResult::NotSupported),
146146
}
147-
Ok(EmulateItemResult::NeedsJumping)
147+
Ok(EmulateItemResult::NeedsReturn)
148148
}
149149
}
150150

Diff for: src/tools/miri/src/shims/x86/sse.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
212212
}
213213
_ => return Ok(EmulateItemResult::NotSupported),
214214
}
215-
Ok(EmulateItemResult::NeedsJumping)
215+
Ok(EmulateItemResult::NeedsReturn)
216216
}
217217
}

Diff for: src/tools/miri/src/shims/x86/sse2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
388388
}
389389
_ => return Ok(EmulateItemResult::NotSupported),
390390
}
391-
Ok(EmulateItemResult::NeedsJumping)
391+
Ok(EmulateItemResult::NeedsReturn)
392392
}
393393
}

Diff for: src/tools/miri/src/shims/x86/sse3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
5151
}
5252
_ => return Ok(EmulateItemResult::NotSupported),
5353
}
54-
Ok(EmulateItemResult::NeedsJumping)
54+
Ok(EmulateItemResult::NeedsReturn)
5555
}
5656
}

Diff for: src/tools/miri/src/shims/x86/sse41.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
176176
}
177177
_ => return Ok(EmulateItemResult::NotSupported),
178178
}
179-
Ok(EmulateItemResult::NeedsJumping)
179+
Ok(EmulateItemResult::NeedsReturn)
180180
}
181181
}

Diff for: src/tools/miri/src/shims/x86/ssse3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
137137
}
138138
_ => return Ok(EmulateItemResult::NotSupported),
139139
}
140-
Ok(EmulateItemResult::NeedsJumping)
140+
Ok(EmulateItemResult::NeedsReturn)
141141
}
142142
}

0 commit comments

Comments
 (0)