Skip to content

Commit 98c1f0f

Browse files
committed
Adapt to the interpreter refactor in miri
1 parent 62c7fff commit 98c1f0f

File tree

7 files changed

+102
-58
lines changed

7 files changed

+102
-58
lines changed

compiler/rustc_const_eval/src/interpret/terminator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
498498
/// `with_caller_location` indicates whether the caller passed a caller location. Miri
499499
/// implements caller locations without argument passing, but to match `FnAbi` we need to know
500500
/// when those arguments are present.
501-
pub(crate) fn eval_fn_call(
501+
pub fn eval_fn_call(
502502
&mut self,
503503
fn_val: FnVal<'tcx, M::ExtraFnVal>,
504504
(caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),

src/tools/miri/src/helpers.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
999999
link_name: Symbol,
10001000
) -> InterpResult<'tcx, ()> {
10011001
self.check_abi(abi, exp_abi)?;
1002-
if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
1002+
if let Some(instance) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
10031003
// If compiler-builtins is providing the symbol, then don't treat it as a clash.
10041004
// We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
10051005
// performance. Note that this means we won't catch any undefined behavior in
@@ -1009,6 +1009,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10091009
return Ok(());
10101010
}
10111011

1012+
let body = self.eval_context_mut().load_mir(instance.def, None)?;
1013+
10121014
throw_machine_stop!(TerminationInfo::SymbolShimClashing {
10131015
link_name,
10141016
span: body.span.data(),

src/tools/miri/src/machine.rs

+19-21
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ use rustc_middle::{
2828
};
2929
use rustc_span::def_id::{CrateNum, DefId};
3030
use rustc_span::{Span, SpanData, Symbol};
31+
use rustc_target::abi::call::FnAbi;
3132
use rustc_target::abi::{Align, Size};
3233
use rustc_target::spec::abi::Abi;
3334

35+
use crate::shims::foreign_items::ExtraFnVal;
3436
use crate::{
3537
concurrency::{data_race, weak_memory},
3638
shims::unix::FileHandler,
@@ -853,7 +855,7 @@ impl<'mir, 'tcx> MiriInterpCxExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {
853855
/// Machine hook implementations.
854856
impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
855857
type MemoryKind = MiriMemoryKind;
856-
type ExtraFnVal = DynSym;
858+
type ExtraFnVal = ExtraFnVal;
857859

858860
type FrameExtra = FrameExtra<'tcx>;
859861
type AllocExtra = AllocExtra<'tcx>;
@@ -938,44 +940,40 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
938940
}
939941

940942
#[inline(always)]
941-
fn find_mir_or_eval_fn(
943+
fn find_mir_or_extra_fn(
942944
ecx: &mut MiriInterpCx<'mir, 'tcx>,
943945
instance: ty::Instance<'tcx>,
944946
abi: Abi,
945-
args: &[FnArg<'tcx, Provenance>],
946-
dest: &PlaceTy<'tcx, Provenance>,
947-
ret: Option<mir::BasicBlock>,
948-
unwind: mir::UnwindAction,
949-
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
950-
// For foreign items, try to see if we can emulate them.
947+
) -> InterpResult<'tcx, Either<&'mir mir::Body<'tcx>, ExtraFnVal>> {
948+
// For foreign items, we return `ExtraFnVal::ForeignFn` to later try to see if we can
949+
// emulate them.
951950
if ecx.tcx.is_foreign_item(instance.def_id()) {
952-
// An external function call that does not have a MIR body. We either find MIR elsewhere
953-
// or emulate its effect.
954-
// This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
955-
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
956-
// foreign function
957-
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
958-
let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
959951
let link_name = ecx.item_link_name(instance.def_id());
960-
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
952+
return Ok(Either::Right(ExtraFnVal::ForeignFn { link_name }));
961953
}
962954

963955
// Otherwise, load the MIR.
964-
Ok(Some((ecx.load_mir(instance.def, None)?, instance)))
956+
ecx.load_mir(instance.def, None).map(Either::Left)
965957
}
966958

967959
#[inline(always)]
968960
fn call_extra_fn(
969961
ecx: &mut MiriInterpCx<'mir, 'tcx>,
970-
fn_val: DynSym,
971-
abi: Abi,
962+
fn_val: ExtraFnVal,
963+
abis: (Abi, &FnAbi<'tcx, Ty<'tcx>>),
972964
args: &[FnArg<'tcx, Provenance>],
973965
dest: &PlaceTy<'tcx, Provenance>,
974966
ret: Option<mir::BasicBlock>,
975967
unwind: mir::UnwindAction,
976968
) -> InterpResult<'tcx> {
977-
let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
978-
ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
969+
match fn_val {
970+
// An external function call that does not have a MIR body. We either find MIR elsewhere
971+
// or emulate its effect.
972+
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
973+
ExtraFnVal::ForeignFn { link_name } =>
974+
ecx.emulate_foreign_item(link_name, abis, &args, dest, ret, unwind).map(|_| ()),
975+
ExtraFnVal::DynSym(sym) => ecx.emulate_dyn_sym(sym, abis, &args, dest, ret, unwind),
976+
}
979977
}
980978

981979
#[inline(always)]

src/tools/miri/src/shims/extern_static.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Provides the `extern static` that this platform expects.
22
3-
use crate::*;
3+
use crate::{shims::foreign_items::ExtraFnVal, *};
44

55
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
66
fn alloc_extern_static(
@@ -62,7 +62,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
6262
// "signal" -- just needs a non-zero pointer value (function does not even get called),
6363
// but we arrange for this to call the `signal` function anyway.
6464
let layout = this.machine.layouts.const_raw_ptr;
65-
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
65+
let ptr = this.fn_ptr(FnVal::Other(ExtraFnVal::DynSym(DynSym::from_str("signal"))));
6666
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
6767
Self::alloc_extern_static(this, "signal", val)?;
6868
}

src/tools/miri/src/shims/foreign_items.rs

+73-31
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,32 @@ use rustc_hir::{
88
def::DefKind,
99
def_id::{CrateNum, LOCAL_CRATE},
1010
};
11-
use rustc_middle::middle::{
12-
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
13-
exported_symbols::ExportedSymbol,
14-
};
1511
use rustc_middle::mir;
1612
use rustc_middle::ty;
13+
use rustc_middle::{
14+
middle::{
15+
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
16+
exported_symbols::ExportedSymbol,
17+
},
18+
ty::Ty,
19+
};
1720
use rustc_session::config::CrateType;
1821
use rustc_span::Symbol;
1922
use rustc_target::{
20-
abi::{Align, Size},
23+
abi::{call::FnAbi, Align, Size},
2124
spec::abi::Abi,
2225
};
2326

2427
use super::backtrace::EvalContextExt as _;
2528
use crate::*;
2629
use helpers::{ToHost, ToSoft};
2730

31+
#[derive(Debug, Copy, Clone)]
32+
pub enum ExtraFnVal {
33+
ForeignFn { link_name: Symbol },
34+
DynSym(DynSym),
35+
}
36+
2837
/// Type of dynamic symbols (for `dlsym` et al)
2938
#[derive(Debug, Copy, Clone)]
3039
pub struct DynSym(Symbol);
@@ -57,12 +66,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
5766
fn emulate_foreign_item(
5867
&mut self,
5968
link_name: Symbol,
60-
abi: Abi,
61-
args: &[OpTy<'tcx, Provenance>],
69+
(abi, fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
70+
args: &[FnArg<'tcx, Provenance>],
6271
dest: &PlaceTy<'tcx, Provenance>,
6372
ret: Option<mir::BasicBlock>,
6473
unwind: mir::UnwindAction,
65-
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
74+
) -> InterpResult<'tcx, Option<()>> {
6675
let this = self.eval_context_mut();
6776
let tcx = this.tcx.tcx;
6877

@@ -71,67 +80,102 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7180
None =>
7281
match link_name.as_str() {
7382
"miri_start_panic" => {
83+
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
84+
7485
// `check_shim` happens inside `handle_miri_start_panic`.
75-
this.handle_miri_start_panic(abi, link_name, args, unwind)?;
86+
this.handle_miri_start_panic(abi, link_name, &args, unwind)?;
7687
return Ok(None);
7788
}
7889
// This matches calls to the foreign item `panic_impl`.
7990
// The implementation is provided by the function with the `#[panic_handler]` attribute.
8091
"panic_impl" => {
8192
// We don't use `check_shim` here because we are just forwarding to the lang
82-
// item. Argument count checking will be performed when the returned `Body` is
83-
// called.
93+
// item. Argument count checking will be performed in `eval_fn_call`.
8494
this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
8595
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
8696
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
87-
return Ok(Some((
88-
this.load_mir(panic_impl_instance.def, None)?,
89-
panic_impl_instance,
90-
)));
97+
98+
this.eval_fn_call(
99+
FnVal::Instance(panic_impl_instance),
100+
(abi, fn_abi),
101+
args,
102+
false,
103+
dest,
104+
ret,
105+
unwind,
106+
)?;
107+
108+
return Ok(Some(()));
91109
}
92110
#[rustfmt::skip]
93-
| "exit"
111+
"exit"
94112
| "ExitProcess"
95113
=> {
96114
let exp_abi = if link_name.as_str() == "exit" {
97115
Abi::C { unwind: false }
98116
} else {
99117
Abi::System { unwind: false }
100118
};
101-
let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
119+
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
120+
let [code] = this.check_shim(abi, exp_abi, link_name, &args)?;
102121
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
103122
let code = this.read_scalar(code)?.to_i32()?;
104123
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
105124
}
106125
"abort" => {
107-
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
126+
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
127+
let [] =
128+
this.check_shim(abi, Abi::C { unwind: false }, link_name, &args)?;
108129
throw_machine_stop!(TerminationInfo::Abort(
109130
"the program aborted execution".to_owned()
110131
))
111132
}
112133
_ => {
113-
if let Some(body) = this.lookup_exported_symbol(link_name)? {
114-
return Ok(Some(body));
134+
if let Some(instance) = this.lookup_exported_symbol(link_name)? {
135+
this.eval_fn_call(
136+
FnVal::Instance(instance),
137+
(abi, fn_abi),
138+
args,
139+
false,
140+
dest,
141+
ret,
142+
unwind,
143+
)?;
144+
145+
return Ok(Some(()));
115146
}
147+
116148
this.handle_unsupported(format!(
117149
"can't call (diverging) foreign function: {link_name}"
118150
))?;
151+
119152
return Ok(None);
120153
}
121154
},
122155
Some(p) => p,
123156
};
124157

125158
// Second: functions that return immediately.
126-
match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
159+
let args2 = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
160+
match this.emulate_foreign_item_inner(link_name, abi, &args2, dest)? {
127161
EmulateForeignItemResult::NeedsJumping => {
128162
trace!("{:?}", this.dump_place(dest));
129163
this.go_to_block(ret);
130164
}
131165
EmulateForeignItemResult::AlreadyJumped => (),
132166
EmulateForeignItemResult::NotSupported => {
133-
if let Some(body) = this.lookup_exported_symbol(link_name)? {
134-
return Ok(Some(body));
167+
if let Some(instance) = this.lookup_exported_symbol(link_name)? {
168+
this.eval_fn_call(
169+
FnVal::Instance(instance),
170+
(abi, fn_abi),
171+
args,
172+
false,
173+
dest,
174+
Some(ret),
175+
unwind,
176+
)?;
177+
178+
return Ok(Some(()));
135179
}
136180

137181
this.handle_unsupported(format!(
@@ -149,13 +193,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
149193
fn emulate_dyn_sym(
150194
&mut self,
151195
sym: DynSym,
152-
abi: Abi,
153-
args: &[OpTy<'tcx, Provenance>],
196+
abis: (Abi, &FnAbi<'tcx, Ty<'tcx>>),
197+
args: &[FnArg<'tcx, Provenance>],
154198
dest: &PlaceTy<'tcx, Provenance>,
155199
ret: Option<mir::BasicBlock>,
156200
unwind: mir::UnwindAction,
157201
) -> InterpResult<'tcx> {
158-
let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?;
202+
let res = self.emulate_foreign_item(sym.0, abis, args, dest, ret, unwind)?;
159203
assert!(res.is_none(), "DynSyms that delegate are not supported");
160204
Ok(())
161205
}
@@ -164,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
164208
fn lookup_exported_symbol(
165209
&mut self,
166210
link_name: Symbol,
167-
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
211+
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
168212
let this = self.eval_context_mut();
169213
let tcx = this.tcx.tcx;
170214

@@ -248,10 +292,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
248292
e.insert(instance_and_crate.map(|ic| ic.0))
249293
}
250294
};
251-
match instance {
252-
None => Ok(None), // no symbol with this name
253-
Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))),
254-
}
295+
296+
Ok(instance)
255297
}
256298

257299
fn malloc(

src/tools/miri/src/shims/unix/foreign_items.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_span::Symbol;
88
use rustc_target::abi::{Align, Size};
99
use rustc_target::spec::abi::Abi;
1010

11+
use crate::shims::foreign_items::ExtraFnVal;
1112
use crate::*;
1213
use shims::foreign_items::EmulateForeignItemResult;
1314
use shims::unix::fs::EvalContextExt as _;
@@ -309,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
309310
let symbol = this.read_pointer(symbol)?;
310311
let name = this.read_c_str(symbol)?;
311312
if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) {
312-
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
313+
let ptr = this.fn_ptr(FnVal::Other(ExtraFnVal::DynSym(DynSym::from_str(name))));
313314
this.write_pointer(ptr, dest)?;
314315
} else {
315316
this.write_null(dest)?;

src/tools/miri/src/shims/windows/foreign_items.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_span::Symbol;
55
use rustc_target::abi::Size;
66
use rustc_target::spec::abi::Abi;
77

8+
use crate::shims::foreign_items::ExtraFnVal;
89
use crate::*;
910
use shims::foreign_items::EmulateForeignItemResult;
1011
use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
@@ -366,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
366367
if let Ok(name) = str::from_utf8(name)
367368
&& is_dyn_sym(name)
368369
{
369-
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
370+
let ptr = this.fn_ptr(FnVal::Other(ExtraFnVal::DynSym(DynSym::from_str(name))));
370371
this.write_pointer(ptr, dest)?;
371372
} else {
372373
this.write_null(dest)?;

0 commit comments

Comments
 (0)