Unsupported foreign non-"C"/"system"-ABI function calls are not UB
This commit is contained in:
parent
1c7d7471da
commit
bbc348539b
@ -13,6 +13,36 @@ use crate::*;
|
||||
use super::backtrace::EvalContextExt as _;
|
||||
use helpers::{check_abi, check_arg_count};
|
||||
|
||||
/// This macro behaves just like `match $link_name { ... }`, but inserts a
|
||||
/// `$crate::helpers::check_abi($abi, $exp_abi)?` call at each match arm
|
||||
/// except the wildcard one.
|
||||
#[macro_export]
|
||||
macro_rules! match_with_abi_check {
|
||||
($link_name:expr, $abi:expr, $exp_abi:expr, {
|
||||
$(|)? $($pattern:pat)|+ $(if $guard:expr)? => $shim_impl:block
|
||||
$($remaining:tt)+
|
||||
}) => {
|
||||
match ($link_name, $abi, $exp_abi) {
|
||||
($($pattern)|+, abi, exp_abi) $(if $guard)? => {
|
||||
$crate::helpers::check_abi(abi, exp_abi)?;
|
||||
$shim_impl
|
||||
}
|
||||
(link_name, abi, exp_abi) => match_with_abi_check!(
|
||||
link_name,
|
||||
abi,
|
||||
exp_abi,
|
||||
{ $($remaining)* }
|
||||
),
|
||||
}
|
||||
};
|
||||
($link_name:ident, $abi:ident, $exp_abi:ident, {
|
||||
_ => $fallback:expr $(,)?
|
||||
}) => ({
|
||||
let _ = ($link_name, $abi, $exp_abi);
|
||||
$fallback
|
||||
});
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
/// Returns the minimum alignment for the target architecture for allocations of the given size.
|
||||
|
@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::{check_abi, check_arg_count};
|
||||
use helpers::check_arg_count;
|
||||
use shims::posix::fs::EvalContextExt as _;
|
||||
use shims::posix::sync::EvalContextExt as _;
|
||||
use shims::posix::thread::EvalContextExt as _;
|
||||
@ -22,9 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
check_abi(abi, Abi::C { unwind: false })?;
|
||||
|
||||
match link_name {
|
||||
match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, {
|
||||
// Environment related shims
|
||||
"getenv" => {
|
||||
let &[ref name] = check_arg_count(args)?;
|
||||
@ -458,12 +456,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
// Platform-specific shims
|
||||
_ => {
|
||||
match this.tcx.sess.target.os.as_str() {
|
||||
"linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
|
||||
"macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
|
||||
"linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
|
||||
"macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use rustc_middle::mir;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use crate::helpers::check_arg_count;
|
||||
@ -12,13 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn emulate_foreign_item_by_name(
|
||||
&mut self,
|
||||
link_name: &str,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
_ret: mir::BasicBlock,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match link_name {
|
||||
match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, {
|
||||
// errno
|
||||
"__errno_location" => {
|
||||
let &[] = check_arg_count(args)?;
|
||||
@ -189,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
}
|
||||
|
||||
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
|
||||
};
|
||||
});
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use rustc_middle::mir;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::check_arg_count;
|
||||
@ -10,13 +11,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
fn emulate_foreign_item_by_name(
|
||||
&mut self,
|
||||
link_name: &str,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: &PlaceTy<'tcx, Tag>,
|
||||
_ret: mir::BasicBlock,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
match link_name {
|
||||
match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, {
|
||||
// errno
|
||||
"__error" => {
|
||||
let &[] = check_arg_count(args)?;
|
||||
@ -83,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
let &[ref info] = check_arg_count(args)?;
|
||||
let result = this.mach_timebase_info(info)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
},
|
||||
}
|
||||
|
||||
// Access to command-line arguments
|
||||
"_NSGetArgc" => {
|
||||
@ -136,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
}
|
||||
|
||||
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
|
||||
};
|
||||
});
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use rustc_target::abi::Size;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use helpers::{check_abi, check_arg_count};
|
||||
use helpers::check_arg_count;
|
||||
use shims::windows::sync::EvalContextExt as _;
|
||||
|
||||
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
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
check_abi(abi, Abi::System { unwind: false })?;
|
||||
|
||||
// Windows API stubs.
|
||||
// HANDLE = isize
|
||||
// DWORD = ULONG = u32
|
||||
// BOOL = i32
|
||||
// BOOLEAN = u8
|
||||
match link_name {
|
||||
match_with_abi_check!(link_name, abi, Abi::System { unwind: false }, {
|
||||
// Environment related shims
|
||||
"GetEnvironmentVariableW" => {
|
||||
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
|
||||
}
|
||||
|
||||
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
9
tests/compile-fail/unsupported_foreign_function.rs
Normal file
9
tests/compile-fail/unsupported_foreign_function.rs
Normal file
@ -0,0 +1,9 @@
|
||||
fn main() {
|
||||
extern "Rust" {
|
||||
fn foo();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
foo(); //~ ERROR unsupported operation: can't call foreign function: foo
|
||||
}
|
||||
}
|
14
tests/compile-fail/unsupported_posix_dlsym.rs
Normal file
14
tests/compile-fail/unsupported_posix_dlsym.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// ignore-windows: No dlsym() on Windows
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
libc::dlsym(ptr::null_mut(), b"foo\0".as_ptr().cast());
|
||||
//~^ ERROR unsupported operation: unsupported
|
||||
}
|
||||
}
|
18
tests/compile-fail/unsupported_windows_dlsym.rs
Normal file
18
tests/compile-fail/unsupported_windows_dlsym.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// ignore-linux: GetProcAddress() is not available on Linux
|
||||
// ignore-macos: GetProcAddress() is not available on macOS
|
||||
|
||||
use std::{ffi::c_void, os::raw::c_char, ptr};
|
||||
|
||||
extern "system" {
|
||||
fn GetProcAddress(
|
||||
hModule: *mut c_void,
|
||||
lpProcName: *const c_char,
|
||||
) -> extern "system" fn() -> isize;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
GetProcAddress(ptr::null_mut(), b"foo\0".as_ptr().cast());
|
||||
//~^ ERROR unsupported operation: unsupported Windows dlsym: foo
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user