Unsupported foreign non-"C"/"system"-ABI function calls are not UB

This commit is contained in:
hyd-dev 2021-03-17 04:21:17 +08:00
parent 1c7d7471da
commit bbc348539b
No known key found for this signature in database
GPG Key ID: 74FA7FD5B8DA14B8
8 changed files with 88 additions and 17 deletions

@ -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)
}

@ -0,0 +1,9 @@
fn main() {
extern "Rust" {
fn foo();
}
unsafe {
foo(); //~ ERROR unsupported operation: can't call foreign function: foo
}
}

@ -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
}
}

@ -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
}
}