Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
if callee_abi != caller_abi {
throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name())
}
check_abi(caller_abi, callee_abi)?;

// Push frame.
let mir = &*this.load_mir(f.def, None)?;
Expand Down
30 changes: 30 additions & 0 deletions src/shims/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 5 additions & 7 deletions src/shims/posix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _;
Expand All @@ -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)?;
Expand Down Expand Up @@ -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)
}
Expand Down
6 changes: 4 additions & 2 deletions src/shims/posix/linux/foreign_items.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;

use crate::*;
use crate::helpers::check_arg_count;
Expand All @@ -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)?;
Expand Down Expand Up @@ -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)
}
Expand Down
8 changes: 5 additions & 3 deletions src/shims/posix/macos/foreign_items.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_middle::mir;
use rustc_target::spec::abi::Abi;

use crate::*;
use helpers::check_arg_count;
Expand All @@ -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)?;
Expand Down Expand Up @@ -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" => {
Expand Down Expand Up @@ -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)
}
Expand Down
8 changes: 3 additions & 5 deletions src/shims/windows/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {}
Expand All @@ -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)?;
Expand Down Expand Up @@ -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)
}
Expand Down
9 changes: 9 additions & 0 deletions tests/compile-fail/unsupported_foreign_function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn main() {
extern "Rust" {
fn foo();
}

unsafe {
foo(); //~ ERROR unsupported operation: can't call foreign function: foo
}
}
14 changes: 14 additions & 0 deletions tests/compile-fail/unsupported_posix_dlsym.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions tests/compile-fail/unsupported_windows_dlsym.rs
Original file line number Diff line number Diff line change
@@ -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
}
}