Skip to content

Commit 6d843ef

Browse files
author
Nym Seddon
committed
Add ABI check for shims
1 parent de0800e commit 6d843ef

File tree

11 files changed

+80
-18
lines changed

11 files changed

+80
-18
lines changed

src/helpers.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_middle::mir;
99
use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout};
1010
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
1111
use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants};
12+
use rustc_target::spec::abi::Abi;
1213

1314
use rand::RngCore;
1415

@@ -553,6 +554,15 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) ->
553554
throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
554555
}
555556

557+
/// Check that the ABI is what we expect.
558+
pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
559+
if abi == exp_abi {
560+
Ok(())
561+
} else {
562+
throw_ub_format!("calling a function with ABI {:?} using caller ABI {:?}", exp_abi, abi)
563+
}
564+
}
565+
556566
pub fn isolation_error(name: &str) -> InterpResult<'static> {
557567
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
558568
"{} not available when isolation is enabled",

src/machine.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,24 +353,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
353353
fn find_mir_or_eval_fn(
354354
ecx: &mut InterpCx<'mir, 'tcx, Self>,
355355
instance: ty::Instance<'tcx>,
356-
_abi: Abi,
356+
abi: Abi,
357357
args: &[OpTy<'tcx, Tag>],
358358
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
359359
unwind: Option<mir::BasicBlock>,
360360
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
361-
ecx.find_mir_or_eval_fn(instance, args, ret, unwind)
361+
ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind)
362362
}
363363

364364
#[inline(always)]
365365
fn call_extra_fn(
366366
ecx: &mut InterpCx<'mir, 'tcx, Self>,
367367
fn_val: Dlsym,
368-
_abi: Abi,
368+
abi: Abi,
369369
args: &[OpTy<'tcx, Tag>],
370370
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
371371
_unwind: Option<mir::BasicBlock>,
372372
) -> InterpResult<'tcx> {
373-
ecx.call_dlsym(fn_val, args, ret)
373+
ecx.call_dlsym(fn_val, abi, args, ret)
374374
}
375375

376376
#[inline(always)]

src/shims/dlsym.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_middle::mir;
2+
use rustc_target::spec::abi::Abi;
23

34
use crate::*;
45
use shims::posix::dlsym as posix;
@@ -29,13 +30,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2930
fn call_dlsym(
3031
&mut self,
3132
dlsym: Dlsym,
33+
abi: Abi,
3234
args: &[OpTy<'tcx, Tag>],
3335
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
3436
) -> InterpResult<'tcx> {
3537
let this = self.eval_context_mut();
3638
match dlsym {
37-
Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, args, ret),
38-
Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, args, ret),
39+
Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret),
40+
Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret),
3941
}
4042
}
4143
}

src/shims/foreign_items.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ use log::trace;
44

55
use rustc_hir::def_id::DefId;
66
use rustc_middle::mir;
7-
use rustc_target::{abi::{Align, Size}, spec::PanicStrategy};
7+
use rustc_target::{abi::{Align, Size}, spec::{PanicStrategy, abi::Abi}};
88
use rustc_middle::ty;
99
use rustc_apfloat::Float;
1010
use rustc_span::symbol::sym;
1111

1212
use crate::*;
1313
use super::backtrace::EvalContextExt as _;
14-
use helpers::check_arg_count;
14+
use helpers::{check_abi, check_arg_count};
1515

1616
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
1717
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
@@ -112,6 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
112112
fn emulate_foreign_item(
113113
&mut self,
114114
def_id: DefId,
115+
abi: Abi,
115116
args: &[OpTy<'tcx, Tag>],
116117
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
117118
unwind: Option<mir::BasicBlock>,
@@ -130,25 +131,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
130131
let (dest, ret) = match ret {
131132
None => match link_name {
132133
"miri_start_panic" => {
134+
check_abi(abi, Abi::Rust)?;
133135
this.handle_miri_start_panic(args, unwind)?;
134136
return Ok(None);
135137
}
136138
// This matches calls to the foreign item `panic_impl`.
137139
// The implementation is provided by the function with the `#[panic_handler]` attribute.
138140
"panic_impl" => {
141+
check_abi(abi, Abi::Rust)?;
139142
let panic_impl_id = tcx.lang_items().panic_impl().unwrap();
140143
let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id);
141144
return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?));
142145
}
143146
| "exit"
144147
| "ExitProcess"
145148
=> {
149+
check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?;
146150
let &[code] = check_arg_count(args)?;
147151
// it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway
148152
let code = this.read_scalar(code)?.to_i32()?;
149153
throw_machine_stop!(TerminationInfo::Exit(code.into()));
150154
}
151155
"abort" => {
156+
check_abi(abi, Abi::C)?;
152157
throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned()))
153158
}
154159
_ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name),
@@ -165,6 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
165170
// Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could
166171
// also be a custom user-provided implementation via `#![feature(panic_runtime)]`
167172
"__rust_start_panic" | "__rust_panic_cleanup" => {
173+
check_abi(abi, Abi::C)?;
168174
// This replicates some of the logic in `inject_panic_runtime`.
169175
// FIXME: is there a way to reuse that logic?
170176
let panic_runtime = match this.tcx.sess.panic_strategy() {
@@ -179,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
179185
}
180186

181187
// Third: functions that return.
182-
if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? {
188+
if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? {
183189
trace!("{:?}", this.dump_place(*dest));
184190
this.go_to_block(ret);
185191
}
@@ -193,6 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
193199
fn emulate_foreign_item_by_name(
194200
&mut self,
195201
link_name: &str,
202+
abi: Abi,
196203
args: &[OpTy<'tcx, Tag>],
197204
dest: PlaceTy<'tcx, Tag>,
198205
ret: mir::BasicBlock,
@@ -204,6 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
204211
match link_name {
205212
// Miri-specific extern functions
206213
"miri_static_root" => {
214+
check_abi(abi, Abi::Rust)?;
207215
let &[ptr] = check_arg_count(args)?;
208216
let ptr = this.read_scalar(ptr)?.check_init()?;
209217
let ptr = this.force_ptr(ptr)?;
@@ -215,23 +223,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
215223

216224
// Obtains a Miri backtrace. See the README for details.
217225
"miri_get_backtrace" => {
226+
check_abi(abi, Abi::Rust)?;
218227
this.handle_miri_get_backtrace(args, dest)?;
219228
}
220229

221230
// Resolves a Miri backtrace frame. See the README for details.
222231
"miri_resolve_frame" => {
232+
check_abi(abi, Abi::Rust)?;
223233
this.handle_miri_resolve_frame(args, dest)?;
224234
}
225235

226236

227237
// Standard C allocation
228238
"malloc" => {
239+
check_abi(abi, Abi::C)?;
229240
let &[size] = check_arg_count(args)?;
230241
let size = this.read_scalar(size)?.to_machine_usize(this)?;
231242
let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C);
232243
this.write_scalar(res, dest)?;
233244
}
234245
"calloc" => {
246+
check_abi(abi, Abi::C)?;
235247
let &[items, len] = check_arg_count(args)?;
236248
let items = this.read_scalar(items)?.to_machine_usize(this)?;
237249
let len = this.read_scalar(len)?.to_machine_usize(this)?;
@@ -241,11 +253,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
241253
this.write_scalar(res, dest)?;
242254
}
243255
"free" => {
256+
check_abi(abi, Abi::C)?;
244257
let &[ptr] = check_arg_count(args)?;
245258
let ptr = this.read_scalar(ptr)?.check_init()?;
246259
this.free(ptr, MiriMemoryKind::C)?;
247260
}
248261
"realloc" => {
262+
check_abi(abi, Abi::C)?;
249263
let &[old_ptr, new_size] = check_arg_count(args)?;
250264
let old_ptr = this.read_scalar(old_ptr)?.check_init()?;
251265
let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?;
@@ -257,6 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
257271
// (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic
258272
// allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.)
259273
"__rust_alloc" => {
274+
check_abi(abi, Abi::Rust)?;
260275
let &[size, align] = check_arg_count(args)?;
261276
let size = this.read_scalar(size)?.to_machine_usize(this)?;
262277
let align = this.read_scalar(align)?.to_machine_usize(this)?;
@@ -269,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
269284
this.write_scalar(ptr, dest)?;
270285
}
271286
"__rust_alloc_zeroed" => {
287+
check_abi(abi, Abi::Rust)?;
272288
let &[size, align] = check_arg_count(args)?;
273289
let size = this.read_scalar(size)?.to_machine_usize(this)?;
274290
let align = this.read_scalar(align)?.to_machine_usize(this)?;
@@ -283,6 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
283299
this.write_scalar(ptr, dest)?;
284300
}
285301
"__rust_dealloc" => {
302+
check_abi(abi, Abi::Rust)?;
286303
let &[ptr, old_size, align] = check_arg_count(args)?;
287304
let ptr = this.read_scalar(ptr)?.check_init()?;
288305
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
@@ -296,6 +313,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
296313
)?;
297314
}
298315
"__rust_realloc" => {
316+
check_abi(abi, Abi::Rust)?;
299317
let &[ptr, old_size, align, new_size] = check_arg_count(args)?;
300318
let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?;
301319
let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?;
@@ -316,6 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
316334

317335
// C memory handling functions
318336
"memcmp" => {
337+
check_abi(abi, Abi::C)?;
319338
let &[left, right, n] = check_arg_count(args)?;
320339
let left = this.read_scalar(left)?.check_init()?;
321340
let right = this.read_scalar(right)?.check_init()?;
@@ -336,6 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
336355
this.write_scalar(Scalar::from_i32(result), dest)?;
337356
}
338357
"memrchr" => {
358+
check_abi(abi, Abi::C)?;
339359
let &[ptr, val, num] = check_arg_count(args)?;
340360
let ptr = this.read_scalar(ptr)?.check_init()?;
341361
let val = this.read_scalar(val)?.to_i32()? as u8;
@@ -354,6 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
354374
}
355375
}
356376
"memchr" => {
377+
check_abi(abi, Abi::C)?;
357378
let &[ptr, val, num] = check_arg_count(args)?;
358379
let ptr = this.read_scalar(ptr)?.check_init()?;
359380
let val = this.read_scalar(val)?.to_i32()? as u8;
@@ -371,6 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
371392
}
372393
}
373394
"strlen" => {
395+
check_abi(abi, Abi::C)?;
374396
let &[ptr] = check_arg_count(args)?;
375397
let ptr = this.read_scalar(ptr)?.check_init()?;
376398
let n = this.memory.read_c_str(ptr)?.len();
@@ -386,6 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
386408
| "asinf"
387409
| "atanf"
388410
=> {
411+
check_abi(abi, Abi::C)?;
389412
let &[f] = check_arg_count(args)?;
390413
// FIXME: Using host floats.
391414
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
@@ -405,6 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
405428
| "hypotf"
406429
| "atan2f"
407430
=> {
431+
check_abi(abi, Abi::C)?;
408432
let &[f1, f2] = check_arg_count(args)?;
409433
// underscore case for windows, here and below
410434
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
@@ -426,6 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
426450
| "asin"
427451
| "atan"
428452
=> {
453+
check_abi(abi, Abi::C)?;
429454
let &[f] = check_arg_count(args)?;
430455
// FIXME: Using host floats.
431456
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
@@ -445,6 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
445470
| "hypot"
446471
| "atan2"
447472
=> {
473+
check_abi(abi, Abi::C)?;
448474
let &[f1, f2] = check_arg_count(args)?;
449475
// FIXME: Using host floats.
450476
let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?);
@@ -460,6 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
460486
| "ldexp"
461487
| "scalbn"
462488
=> {
489+
check_abi(abi, Abi::C)?;
463490
let &[x, exp] = check_arg_count(args)?;
464491
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
465492
let x = this.read_scalar(x)?.to_f64()?;
@@ -481,10 +508,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
481508

482509
// Architecture-specific shims
483510
"llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => {
511+
check_abi(abi, Abi::C)?;
484512
let &[] = check_arg_count(args)?;
485513
this.yield_active_thread();
486514
}
487515
"llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => {
516+
check_abi(abi, Abi::C)?;
488517
let &[hint] = check_arg_count(args)?;
489518
let hint = this.read_scalar(hint)?.to_i32()?;
490519
match hint {
@@ -499,8 +528,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
499528

500529
// Platform-specific shims
501530
_ => match this.tcx.sess.target.os.as_str() {
502-
"linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
503-
"windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
531+
"linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
532+
"windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
504533
target => throw_unsup_format!("the target `{}` is not supported", target),
505534
}
506535
};

src/shims/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub mod tls;
1616
use log::trace;
1717

1818
use rustc_middle::{mir, ty};
19+
use rustc_target::spec::abi::Abi;
1920

2021
use crate::*;
2122
use helpers::check_arg_count;
@@ -25,6 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2526
fn find_mir_or_eval_fn(
2627
&mut self,
2728
instance: ty::Instance<'tcx>,
29+
abi: Abi,
2830
args: &[OpTy<'tcx, Tag>],
2931
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
3032
unwind: Option<mir::BasicBlock>,
@@ -48,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
4850
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
4951
// foreign function
5052
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
51-
return this.emulate_foreign_item(instance.def_id(), args, ret, unwind);
53+
return this.emulate_foreign_item(instance.def_id(), abi, args, ret, unwind);
5254
}
5355

5456
// Otherwise, load the MIR.

src/shims/posix/dlsym.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_middle::mir;
2+
use rustc_target::spec::abi::Abi;
23

34
use crate::*;
45
use shims::posix::linux::dlsym as linux;
@@ -27,13 +28,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2728
fn call_dlsym(
2829
&mut self,
2930
dlsym: Dlsym,
31+
abi: Abi,
3032
args: &[OpTy<'tcx, Tag>],
3133
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
3234
) -> InterpResult<'tcx> {
3335
let this = self.eval_context_mut();
3436
match dlsym {
35-
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret),
36-
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret),
37+
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret),
38+
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret),
3739
}
3840
}
3941
}

0 commit comments

Comments
 (0)