Skip to content

Commit 71f4140

Browse files
author
hyd-dev
committed
Add -Zmiri-disable-abi-check
1 parent 178ae8e commit 71f4140

File tree

16 files changed

+235
-174
lines changed

16 files changed

+235
-174
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ environment variable:
214214
as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs
215215
in your program. However, this can also help to make Miri run faster. Using
216216
this flag is **unsound**.
217+
* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag
218+
is **unsound**.
217219
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
218220
the program has access to host resources such as environment variables, file
219221
systems, and randomness.
@@ -263,6 +265,8 @@ environment variable:
263265
with `-Zmiri-track-raw-pointers` also works without
264266
`-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case.
265267

268+
[function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
269+
266270
Some native rustc `-Z` flags are also very relevant for Miri:
267271

268272
* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri

src/bin/miri.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ fn main() {
227227
"-Zmiri-symbolic-alignment-check" => {
228228
miri_config.check_alignment = miri::AlignmentCheck::Symbolic;
229229
}
230+
"-Zmiri-disable-abi-check" => {
231+
miri_config.check_abi = false;
232+
}
230233
"-Zmiri-disable-isolation" => {
231234
miri_config.communicate = true;
232235
}

src/eval.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub struct MiriConfig {
3131
pub stacked_borrows: bool,
3232
/// Controls alignment checking.
3333
pub check_alignment: AlignmentCheck,
34+
/// Controls function [ABI](Abi) checking.
35+
pub check_abi: bool,
3436
/// Determines if communication with the host environment is enabled.
3537
pub communicate: bool,
3638
/// Determines if memory leaks should be ignored.
@@ -65,6 +67,7 @@ impl Default for MiriConfig {
6567
validate: true,
6668
stacked_borrows: true,
6769
check_alignment: AlignmentCheck::Int,
70+
check_abi: true,
6871
communicate: false,
6972
ignore_leaks: false,
7073
excluded_env_vars: vec![],

src/helpers.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
165165
let this = self.eval_context_mut();
166166
let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
167167
let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
168-
if callee_abi != caller_abi {
168+
if this.machine.enforce_abi && callee_abi != caller_abi {
169169
throw_ub_format!(
170170
"calling a function with ABI {} using caller ABI {}",
171171
callee_abi.name(),
@@ -632,16 +632,19 @@ where
632632
}
633633

634634
/// Check that the ABI is what we expect.
635-
pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
636-
if abi == exp_abi {
637-
Ok(())
638-
} else {
635+
pub fn check_abi<'a>(
636+
this: &MiriEvalContext<'_, '_>,
637+
abi: Abi,
638+
exp_abi: Abi,
639+
) -> InterpResult<'a, ()> {
640+
if this.machine.enforce_abi && abi != exp_abi {
639641
throw_ub_format!(
640642
"calling a function with ABI {} using caller ABI {}",
641643
exp_abi.name(),
642644
abi.name()
643645
)
644646
}
647+
Ok(())
645648
}
646649

647650
pub fn isolation_error(name: &str) -> InterpResult<'static> {

src/machine.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ pub struct Evaluator<'mir, 'tcx> {
270270
/// Whether to enforce the validity invariant.
271271
pub(crate) validate: bool,
272272

273+
/// Whether to enforce [ABI](Abi) of function calls.
274+
pub(crate) enforce_abi: bool,
275+
273276
pub(crate) file_handler: shims::posix::FileHandler,
274277
pub(crate) dir_handler: shims::posix::DirHandler,
275278

@@ -310,6 +313,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
310313
tls: TlsData::default(),
311314
communicate: config.communicate,
312315
validate: config.validate,
316+
enforce_abi: config.check_abi,
313317
file_handler: Default::default(),
314318
dir_handler: Default::default(),
315319
time_anchor: Instant::now(),
@@ -371,6 +375,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
371375
ecx.machine.validate
372376
}
373377

378+
#[inline(always)]
379+
fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
380+
ecx.machine.enforce_abi
381+
}
382+
374383
#[inline(always)]
375384
fn find_mir_or_eval_fn(
376385
ecx: &mut InterpCx<'mir, 'tcx, Self>,

src/shims/foreign_items.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
136136
let (dest, ret) = match ret {
137137
None => match link_name {
138138
"miri_start_panic" => {
139-
check_abi(abi, Abi::Rust)?;
139+
check_abi(this, abi, Abi::Rust)?;
140140
this.handle_miri_start_panic(args, unwind)?;
141141
return Ok(None);
142142
}
143143
// This matches calls to the foreign item `panic_impl`.
144144
// The implementation is provided by the function with the `#[panic_handler]` attribute.
145145
"panic_impl" => {
146-
check_abi(abi, Abi::Rust)?;
146+
check_abi(this, abi, Abi::Rust)?;
147147
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
148148
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
149149
return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?));
@@ -152,14 +152,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
152152
| "exit"
153153
| "ExitProcess"
154154
=> {
155-
check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?;
155+
check_abi(this, abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?;
156156
let &[ref code] = check_arg_count(args)?;
157157
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
158158
let code = this.read_scalar(code)?.to_i32()?;
159159
throw_machine_stop!(TerminationInfo::Exit(code.into()));
160160
}
161161
"abort" => {
162-
check_abi(abi, Abi::C { unwind: false })?;
162+
check_abi(this, abi, Abi::C { unwind: false })?;
163163
throw_machine_stop!(TerminationInfo::Abort(
164164
"the program aborted execution".to_owned()
165165
))
@@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
180180
#[rustfmt::skip]
181181
"__rust_start_panic" |
182182
"__rust_panic_cleanup" => {
183-
check_abi(abi, Abi::C { unwind: false })?;
183+
check_abi(this, abi, Abi::C { unwind: false })?;
184184
// This replicates some of the logic in `inject_panic_runtime`.
185185
// FIXME: is there a way to reuse that logic?
186186
let panic_runtime = match this.tcx.sess.panic_strategy() {
@@ -221,7 +221,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
221221
match link_name {
222222
// Miri-specific extern functions
223223
"miri_static_root" => {
224-
check_abi(abi, Abi::Rust)?;
224+
check_abi(this, abi, Abi::Rust)?;
225225
let &[ref ptr] = check_arg_count(args)?;
226226
let ptr = this.read_scalar(ptr)?.check_init()?;
227227
let ptr = this.force_ptr(ptr)?;
@@ -233,27 +233,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
233233

234234
// Obtains a Miri backtrace. See the README for details.
235235
"miri_get_backtrace" => {
236-
check_abi(abi, Abi::Rust)?;
236+
check_abi(this, abi, Abi::Rust)?;
237237
this.handle_miri_get_backtrace(args, dest)?;
238238
}
239239

240240
// Resolves a Miri backtrace frame. See the README for details.
241241
"miri_resolve_frame" => {
242-
check_abi(abi, Abi::Rust)?;
242+
check_abi(this, abi, Abi::Rust)?;
243243
this.handle_miri_resolve_frame(args, dest)?;
244244
}
245245

246246

247247
// Standard C allocation
248248
"malloc" => {
249-
check_abi(abi, Abi::C { unwind: false })?;
249+
check_abi(this, abi, Abi::C { unwind: false })?;
250250
let &[ref size] = check_arg_count(args)?;
251251
let size = this.read_scalar(size)?.to_machine_usize(this)?;
252252
let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C);
253253
this.write_scalar(res, dest)?;
254254
}
255255
"calloc" => {
256-
check_abi(abi, Abi::C { unwind: false })?;
256+
check_abi(this, abi, Abi::C { unwind: false })?;
257257
let &[ref items, ref len] = check_arg_count(args)?;
258258
let items = this.read_scalar(items)?.to_machine_usize(this)?;
259259
let len = this.read_scalar(len)?.to_machine_usize(this)?;
@@ -263,13 +263,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
263263
this.write_scalar(res, dest)?;
264264
}
265265
"free" => {
266-
check_abi(abi, Abi::C { unwind: false })?;
266+
check_abi(this, abi, Abi::C { unwind: false })?;
267267
let &[ref ptr] = check_arg_count(args)?;
268268
let ptr = this.read_scalar(ptr)?.check_init()?;
269269
this.free(ptr, MiriMemoryKind::C)?;
270270
}
271271
"realloc" => {
272-
check_abi(abi, Abi::C { unwind: false })?;
272+
check_abi(this, abi, Abi::C { unwind: false })?;
273273
let &[ref old_ptr, ref new_size] = check_arg_count(args)?;
274274
let old_ptr = this.read_scalar(old_ptr)?.check_init()?;
275275
let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?;
@@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
281281
// (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic
282282
// allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.)
283283
"__rust_alloc" => {
284-
check_abi(abi, Abi::Rust)?;
284+
check_abi(this, abi, Abi::Rust)?;
285285
let &[ref size, ref align] = check_arg_count(args)?;
286286
let size = this.read_scalar(size)?.to_machine_usize(this)?;
287287
let align = this.read_scalar(align)?.to_machine_usize(this)?;
@@ -294,7 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
294294
this.write_scalar(ptr, dest)?;
295295
}
296296
"__rust_alloc_zeroed" => {
297-
check_abi(abi, Abi::Rust)?;
297+
check_abi(this, abi, Abi::Rust)?;
298298
let &[ref size, ref align] = check_arg_count(args)?;
299299
let size = this.read_scalar(size)?.to_machine_usize(this)?;
300300
let align = this.read_scalar(align)?.to_machine_usize(this)?;
@@ -309,7 +309,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
309309
this.write_scalar(ptr, dest)?;
310310
}
311311
"__rust_dealloc" => {
312-
check_abi(abi, Abi::Rust)?;
312+
check_abi(this, abi, Abi::Rust)?;
313313
let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?;
314314
let ptr = this.read_scalar(ptr)?.check_init()?;
315315
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
@@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
323323
)?;
324324
}
325325
"__rust_realloc" => {
326-
check_abi(abi, Abi::Rust)?;
326+
check_abi(this, abi, Abi::Rust)?;
327327
let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?;
328328
let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?;
329329
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
@@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
344344

345345
// C memory handling functions
346346
"memcmp" => {
347-
check_abi(abi, Abi::C { unwind: false })?;
347+
check_abi(this, abi, Abi::C { unwind: false })?;
348348
let &[ref left, ref right, ref n] = check_arg_count(args)?;
349349
let left = this.read_scalar(left)?.check_init()?;
350350
let right = this.read_scalar(right)?.check_init()?;
@@ -365,7 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
365365
this.write_scalar(Scalar::from_i32(result), dest)?;
366366
}
367367
"memrchr" => {
368-
check_abi(abi, Abi::C { unwind: false })?;
368+
check_abi(this, abi, Abi::C { unwind: false })?;
369369
let &[ref ptr, ref val, ref num] = check_arg_count(args)?;
370370
let ptr = this.read_scalar(ptr)?.check_init()?;
371371
let val = this.read_scalar(val)?.to_i32()? as u8;
@@ -384,7 +384,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
384384
}
385385
}
386386
"memchr" => {
387-
check_abi(abi, Abi::C { unwind: false })?;
387+
check_abi(this, abi, Abi::C { unwind: false })?;
388388
let &[ref ptr, ref val, ref num] = check_arg_count(args)?;
389389
let ptr = this.read_scalar(ptr)?.check_init()?;
390390
let val = this.read_scalar(val)?.to_i32()? as u8;
@@ -402,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
402402
}
403403
}
404404
"strlen" => {
405-
check_abi(abi, Abi::C { unwind: false })?;
405+
check_abi(this, abi, Abi::C { unwind: false })?;
406406
let &[ref ptr] = check_arg_count(args)?;
407407
let ptr = this.read_scalar(ptr)?.check_init()?;
408408
let n = this.read_c_str(ptr)?.len();
@@ -419,7 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
419419
| "asinf"
420420
| "atanf"
421421
=> {
422-
check_abi(abi, Abi::C { unwind: false })?;
422+
check_abi(this, abi, Abi::C { unwind: false })?;
423423
let &[ref f] = check_arg_count(args)?;
424424
// FIXME: Using host floats.
425425
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
@@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
440440
| "hypotf"
441441
| "atan2f"
442442
=> {
443-
check_abi(abi, Abi::C { unwind: false })?;
443+
check_abi(this, abi, Abi::C { unwind: false })?;
444444
let &[ref f1, ref f2] = check_arg_count(args)?;
445445
// underscore case for windows, here and below
446446
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
@@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
463463
| "asin"
464464
| "atan"
465465
=> {
466-
check_abi(abi, Abi::C { unwind: false })?;
466+
check_abi(this, abi, Abi::C { unwind: false })?;
467467
let &[ref f] = check_arg_count(args)?;
468468
// FIXME: Using host floats.
469469
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
@@ -484,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
484484
| "hypot"
485485
| "atan2"
486486
=> {
487-
check_abi(abi, Abi::C { unwind: false })?;
487+
check_abi(this, abi, Abi::C { unwind: false })?;
488488
let &[ref f1, ref f2] = check_arg_count(args)?;
489489
// FIXME: Using host floats.
490490
let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?);
@@ -501,7 +501,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
501501
| "ldexp"
502502
| "scalbn"
503503
=> {
504-
check_abi(abi, Abi::C { unwind: false })?;
504+
check_abi(this, abi, Abi::C { unwind: false })?;
505505
let &[ref x, ref exp] = check_arg_count(args)?;
506506
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
507507
let x = this.read_scalar(x)?.to_f64()?;
@@ -523,12 +523,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
523523

524524
// Architecture-specific shims
525525
"llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => {
526-
check_abi(abi, Abi::C { unwind: false })?;
526+
check_abi(this, abi, Abi::C { unwind: false })?;
527527
let &[] = check_arg_count(args)?;
528528
this.yield_active_thread();
529529
}
530530
"llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => {
531-
check_abi(abi, Abi::C { unwind: false })?;
531+
check_abi(this, abi, Abi::C { unwind: false })?;
532532
let &[ref arg] = check_arg_count(args)?;
533533
let arg = this.read_scalar(arg)?.to_i32()?;
534534
match arg {

src/shims/posix/dlsym.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
3535
) -> InterpResult<'tcx> {
3636
let this = self.eval_context_mut();
3737

38-
check_abi(abi, Abi::C { unwind: false })?;
38+
check_abi(this, abi, Abi::C { unwind: false })?;
3939

4040
match dlsym {
4141
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret),

0 commit comments

Comments
 (0)