Skip to content

Commit e5f7a74

Browse files
committed
Adapt to the interpreter refactor in miri
1 parent c4ecc2b commit e5f7a74

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
@@ -997,7 +997,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
997997
link_name: Symbol,
998998
) -> InterpResult<'tcx, ()> {
999999
self.check_abi(abi, exp_abi)?;
1000-
if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
1000+
if let Some(instance) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
10011001
// If compiler-builtins is providing the symbol, then don't treat it as a clash.
10021002
// We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
10031003
// performance. Note that this means we won't catch any undefined behavior in
@@ -1007,6 +1007,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10071007
return Ok(());
10081008
}
10091009

1010+
let body = self.eval_context_mut().load_mir(instance.def, None)?;
1011+
10101012
throw_machine_stop!(TerminationInfo::SymbolShimClashing {
10111013
link_name,
10121014
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
@@ -6,23 +6,32 @@ use rustc_hir::{
66
def::DefKind,
77
def_id::{CrateNum, LOCAL_CRATE},
88
};
9-
use rustc_middle::middle::{
10-
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
11-
exported_symbols::ExportedSymbol,
12-
};
139
use rustc_middle::mir;
1410
use rustc_middle::ty;
11+
use rustc_middle::{
12+
middle::{
13+
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
14+
exported_symbols::ExportedSymbol,
15+
},
16+
ty::Ty,
17+
};
1518
use rustc_session::config::CrateType;
1619
use rustc_span::Symbol;
1720
use rustc_target::{
18-
abi::{Align, Size},
21+
abi::{call::FnAbi, Align, Size},
1922
spec::abi::Abi,
2023
};
2124

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

29+
#[derive(Debug, Copy, Clone)]
30+
pub enum ExtraFnVal {
31+
ForeignFn { link_name: Symbol },
32+
DynSym(DynSym),
33+
}
34+
2635
/// Type of dynamic symbols (for `dlsym` et al)
2736
#[derive(Debug, Copy, Clone)]
2837
pub struct DynSym(Symbol);
@@ -55,12 +64,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
5564
fn emulate_foreign_item(
5665
&mut self,
5766
link_name: Symbol,
58-
abi: Abi,
59-
args: &[OpTy<'tcx, Provenance>],
67+
(abi, fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
68+
args: &[FnArg<'tcx, Provenance>],
6069
dest: &PlaceTy<'tcx, Provenance>,
6170
ret: Option<mir::BasicBlock>,
6271
unwind: mir::UnwindAction,
63-
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
72+
) -> InterpResult<'tcx, Option<()>> {
6473
let this = self.eval_context_mut();
6574
let tcx = this.tcx.tcx;
6675

@@ -69,67 +78,102 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6978
None =>
7079
match link_name.as_str() {
7180
"miri_start_panic" => {
81+
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
82+
7283
// `check_shim` happens inside `handle_miri_start_panic`.
73-
this.handle_miri_start_panic(abi, link_name, args, unwind)?;
84+
this.handle_miri_start_panic(abi, link_name, &args, unwind)?;
7485
return Ok(None);
7586
}
7687
// This matches calls to the foreign item `panic_impl`.
7788
// The implementation is provided by the function with the `#[panic_handler]` attribute.
7889
"panic_impl" => {
7990
// We don't use `check_shim` here because we are just forwarding to the lang
80-
// item. Argument count checking will be performed when the returned `Body` is
81-
// called.
91+
// item. Argument count checking will be performed in `eval_fn_call`.
8292
this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?;
8393
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
8494
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
85-
return Ok(Some((
86-
this.load_mir(panic_impl_instance.def, None)?,
87-
panic_impl_instance,
88-
)));
95+
96+
this.eval_fn_call(
97+
FnVal::Instance(panic_impl_instance),
98+
(abi, fn_abi),
99+
args,
100+
false,
101+
dest,
102+
ret,
103+
unwind,
104+
)?;
105+
106+
return Ok(Some(()));
89107
}
90108
#[rustfmt::skip]
91-
| "exit"
109+
"exit"
92110
| "ExitProcess"
93111
=> {
94112
let exp_abi = if link_name.as_str() == "exit" {
95113
Abi::C { unwind: false }
96114
} else {
97115
Abi::System { unwind: false }
98116
};
99-
let [code] = this.check_shim(abi, exp_abi, link_name, args)?;
117+
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
118+
let [code] = this.check_shim(abi, exp_abi, link_name, &args)?;
100119
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
101120
let code = this.read_scalar(code)?.to_i32()?;
102121
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
103122
}
104123
"abort" => {
105-
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
124+
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
125+
let [] =
126+
this.check_shim(abi, Abi::C { unwind: false }, link_name, &args)?;
106127
throw_machine_stop!(TerminationInfo::Abort(
107128
"the program aborted execution".to_owned()
108129
))
109130
}
110131
_ => {
111-
if let Some(body) = this.lookup_exported_symbol(link_name)? {
112-
return Ok(Some(body));
132+
if let Some(instance) = this.lookup_exported_symbol(link_name)? {
133+
this.eval_fn_call(
134+
FnVal::Instance(instance),
135+
(abi, fn_abi),
136+
args,
137+
false,
138+
dest,
139+
ret,
140+
unwind,
141+
)?;
142+
143+
return Ok(Some(()));
113144
}
145+
114146
this.handle_unsupported(format!(
115147
"can't call (diverging) foreign function: {link_name}"
116148
))?;
149+
117150
return Ok(None);
118151
}
119152
},
120153
Some(p) => p,
121154
};
122155

123156
// Second: functions that return immediately.
124-
match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
157+
let args2 = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
158+
match this.emulate_foreign_item_inner(link_name, abi, &args2, dest)? {
125159
EmulateForeignItemResult::NeedsJumping => {
126160
trace!("{:?}", this.dump_place(dest));
127161
this.go_to_block(ret);
128162
}
129163
EmulateForeignItemResult::AlreadyJumped => (),
130164
EmulateForeignItemResult::NotSupported => {
131-
if let Some(body) = this.lookup_exported_symbol(link_name)? {
132-
return Ok(Some(body));
165+
if let Some(instance) = this.lookup_exported_symbol(link_name)? {
166+
this.eval_fn_call(
167+
FnVal::Instance(instance),
168+
(abi, fn_abi),
169+
args,
170+
false,
171+
dest,
172+
Some(ret),
173+
unwind,
174+
)?;
175+
176+
return Ok(Some(()));
133177
}
134178

135179
this.handle_unsupported(format!(
@@ -147,13 +191,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
147191
fn emulate_dyn_sym(
148192
&mut self,
149193
sym: DynSym,
150-
abi: Abi,
151-
args: &[OpTy<'tcx, Provenance>],
194+
abis: (Abi, &FnAbi<'tcx, Ty<'tcx>>),
195+
args: &[FnArg<'tcx, Provenance>],
152196
dest: &PlaceTy<'tcx, Provenance>,
153197
ret: Option<mir::BasicBlock>,
154198
unwind: mir::UnwindAction,
155199
) -> InterpResult<'tcx> {
156-
let res = self.emulate_foreign_item(sym.0, abi, args, dest, ret, unwind)?;
200+
let res = self.emulate_foreign_item(sym.0, abis, args, dest, ret, unwind)?;
157201
assert!(res.is_none(), "DynSyms that delegate are not supported");
158202
Ok(())
159203
}
@@ -162,7 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
162206
fn lookup_exported_symbol(
163207
&mut self,
164208
link_name: Symbol,
165-
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
209+
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
166210
let this = self.eval_context_mut();
167211
let tcx = this.tcx.tcx;
168212

@@ -246,10 +290,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
246290
e.insert(instance_and_crate.map(|ic| ic.0))
247291
}
248292
};
249-
match instance {
250-
None => Ok(None), // no symbol with this name
251-
Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))),
252-
}
293+
294+
Ok(instance)
253295
}
254296

255297
fn malloc(

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

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

9+
use crate::shims::foreign_items::ExtraFnVal;
910
use crate::*;
1011
use shims::foreign_items::EmulateForeignItemResult;
1112
use shims::unix::fs::EvalContextExt as _;
@@ -308,7 +309,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
308309
let symbol = this.read_pointer(symbol)?;
309310
let name = this.read_c_str(symbol)?;
310311
if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) {
311-
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
312+
let ptr = this.fn_ptr(FnVal::Other(ExtraFnVal::DynSym(DynSym::from_str(name))));
312313
this.write_pointer(ptr, dest)?;
313314
} else {
314315
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)