Skip to content

Commit bbc3485

Browse files
author
hyd-dev
committed
Unsupported foreign non-"C"/"system"-ABI function calls are not UB
1 parent 1c7d747 commit bbc3485

File tree

8 files changed

+88
-17
lines changed

8 files changed

+88
-17
lines changed

src/shims/foreign_items.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,36 @@ use crate::*;
1313
use super::backtrace::EvalContextExt as _;
1414
use helpers::{check_abi, check_arg_count};
1515

16+
/// This macro behaves just like `match $link_name { ... }`, but inserts a
17+
/// `$crate::helpers::check_abi($abi, $exp_abi)?` call at each match arm
18+
/// except the wildcard one.
19+
#[macro_export]
20+
macro_rules! match_with_abi_check {
21+
($link_name:expr, $abi:expr, $exp_abi:expr, {
22+
$(|)? $($pattern:pat)|+ $(if $guard:expr)? => $shim_impl:block
23+
$($remaining:tt)+
24+
}) => {
25+
match ($link_name, $abi, $exp_abi) {
26+
($($pattern)|+, abi, exp_abi) $(if $guard)? => {
27+
$crate::helpers::check_abi(abi, exp_abi)?;
28+
$shim_impl
29+
}
30+
(link_name, abi, exp_abi) => match_with_abi_check!(
31+
link_name,
32+
abi,
33+
exp_abi,
34+
{ $($remaining)* }
35+
),
36+
}
37+
};
38+
($link_name:ident, $abi:ident, $exp_abi:ident, {
39+
_ => $fallback:expr $(,)?
40+
}) => ({
41+
let _ = ($link_name, $abi, $exp_abi);
42+
$fallback
43+
});
44+
}
45+
1646
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
1747
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
1848
/// Returns the minimum alignment for the target architecture for allocations of the given size.

src/shims/posix/foreign_items.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size};
55
use rustc_target::spec::abi::Abi;
66

77
use crate::*;
8-
use helpers::{check_abi, check_arg_count};
8+
use helpers::check_arg_count;
99
use shims::posix::fs::EvalContextExt as _;
1010
use shims::posix::sync::EvalContextExt as _;
1111
use shims::posix::thread::EvalContextExt as _;
@@ -22,9 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2222
) -> InterpResult<'tcx, bool> {
2323
let this = self.eval_context_mut();
2424

25-
check_abi(abi, Abi::C { unwind: false })?;
26-
27-
match link_name {
25+
match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, {
2826
// Environment related shims
2927
"getenv" => {
3028
let &[ref name] = check_arg_count(args)?;
@@ -458,12 +456,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
458456
// Platform-specific shims
459457
_ => {
460458
match this.tcx.sess.target.os.as_str() {
461-
"linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
462-
"macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
459+
"linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
460+
"macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
463461
_ => unreachable!(),
464462
}
465463
}
466-
};
464+
});
467465

468466
Ok(true)
469467
}

src/shims/posix/linux/foreign_items.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 crate::helpers::check_arg_count;
@@ -12,13 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1213
fn emulate_foreign_item_by_name(
1314
&mut self,
1415
link_name: &str,
16+
abi: Abi,
1517
args: &[OpTy<'tcx, Tag>],
1618
dest: &PlaceTy<'tcx, Tag>,
1719
_ret: mir::BasicBlock,
1820
) -> InterpResult<'tcx, bool> {
1921
let this = self.eval_context_mut();
2022

21-
match link_name {
23+
match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, {
2224
// errno
2325
"__errno_location" => {
2426
let &[] = check_arg_count(args)?;
@@ -189,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
189191
}
190192

191193
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
192-
};
194+
});
193195

194196
Ok(true)
195197
}

src/shims/posix/macos/foreign_items.rs

Lines changed: 5 additions & 3 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 helpers::check_arg_count;
@@ -10,13 +11,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1011
fn emulate_foreign_item_by_name(
1112
&mut self,
1213
link_name: &str,
14+
abi: Abi,
1315
args: &[OpTy<'tcx, Tag>],
1416
dest: &PlaceTy<'tcx, Tag>,
1517
_ret: mir::BasicBlock,
1618
) -> InterpResult<'tcx, bool> {
1719
let this = self.eval_context_mut();
1820

19-
match link_name {
21+
match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, {
2022
// errno
2123
"__error" => {
2224
let &[] = check_arg_count(args)?;
@@ -83,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8385
let &[ref info] = check_arg_count(args)?;
8486
let result = this.mach_timebase_info(info)?;
8587
this.write_scalar(Scalar::from_i32(result), dest)?;
86-
},
88+
}
8789

8890
// Access to command-line arguments
8991
"_NSGetArgc" => {
@@ -136,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
136138
}
137139

138140
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
139-
};
141+
});
140142

141143
Ok(true)
142144
}

src/shims/windows/foreign_items.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_target::abi::Size;
55
use rustc_target::spec::abi::Abi;
66

77
use crate::*;
8-
use helpers::{check_abi, check_arg_count};
8+
use helpers::check_arg_count;
99
use shims::windows::sync::EvalContextExt as _;
1010

1111
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
@@ -20,14 +20,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2020
) -> InterpResult<'tcx, bool> {
2121
let this = self.eval_context_mut();
2222

23-
check_abi(abi, Abi::System { unwind: false })?;
24-
2523
// Windows API stubs.
2624
// HANDLE = isize
2725
// DWORD = ULONG = u32
2826
// BOOL = i32
2927
// BOOLEAN = u8
30-
match link_name {
28+
match_with_abi_check!(link_name, abi, Abi::System { unwind: false }, {
3129
// Environment related shims
3230
"GetEnvironmentVariableW" => {
3331
let &[ref name, ref buf, ref size] = check_arg_count(args)?;
@@ -340,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
340338
}
341339

342340
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
343-
}
341+
});
344342

345343
Ok(true)
346344
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
extern "Rust" {
3+
fn foo();
4+
}
5+
6+
unsafe {
7+
foo(); //~ ERROR unsupported operation: can't call foreign function: foo
8+
}
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// ignore-windows: No dlsym() on Windows
2+
3+
#![feature(rustc_private)]
4+
5+
extern crate libc;
6+
7+
use std::ptr;
8+
9+
fn main() {
10+
unsafe {
11+
libc::dlsym(ptr::null_mut(), b"foo\0".as_ptr().cast());
12+
//~^ ERROR unsupported operation: unsupported
13+
}
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// ignore-linux: GetProcAddress() is not available on Linux
2+
// ignore-macos: GetProcAddress() is not available on macOS
3+
4+
use std::{ffi::c_void, os::raw::c_char, ptr};
5+
6+
extern "system" {
7+
fn GetProcAddress(
8+
hModule: *mut c_void,
9+
lpProcName: *const c_char,
10+
) -> extern "system" fn() -> isize;
11+
}
12+
13+
fn main() {
14+
unsafe {
15+
GetProcAddress(ptr::null_mut(), b"foo\0".as_ptr().cast());
16+
//~^ ERROR unsupported operation: unsupported Windows dlsym: foo
17+
}
18+
}

0 commit comments

Comments
 (0)