Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 3 additions & 5 deletions src/shims/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_span::{BytePos, Loc, Symbol, hygiene};
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;

use crate::helpers::check_min_arg_count;
use crate::*;

impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
Expand Down Expand Up @@ -39,11 +40,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let this = self.eval_context_mut();
let tcx = this.tcx;

let flags = if let Some(flags_op) = args.first() {
this.read_scalar(flags_op)?.to_u64()?
} else {
throw_ub_format!("expected at least 1 argument")
};
let [flags] = check_min_arg_count("miri_get_backtrace", args)?;
let flags = this.read_scalar(flags)?.to_u64()?;

let mut data = Vec::new();
for frame in this.active_thread_stack().iter().rev() {
Expand Down
2 changes: 1 addition & 1 deletion src/shims/unix/linux/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// `futex` is used by some synchronization primitives.
num if num == sys_futex => {
futex(this, &args[1..], dest)?;
futex(this, args, dest)?;
}
num if num == sys_eventfd2 => {
let [_, initval, flags] =
Expand Down
42 changes: 13 additions & 29 deletions src/shims/unix/linux/sync.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::helpers::check_min_arg_count;
use crate::*;

/// Implementation of the SYS_futex syscall.
/// `args` is the arguments *after* the syscall number.
/// `args` is the arguments *including* the syscall number.
pub fn futex<'tcx>(
this: &mut MiriInterpCx<'tcx>,
args: &[OpTy<'tcx>],
Expand All @@ -15,12 +16,7 @@ pub fn futex<'tcx>(
// may or may not be left out from the `syscall()` call.
// Therefore we don't use `check_arg_count` here, but only check for the
// number of arguments to fall within a range.
let [addr, op, val, ..] = args else {
throw_ub_format!(
"incorrect number of arguments for `futex` syscall: got {}, expected at least 3",
args.len()
);
};
let [_, addr, op, val] = check_min_arg_count("`syscall(SYS_futex, ...)`", args)?;

// The first three arguments (after the syscall number itself) are the same to all futex operations:
// (int *addr, int op, int val).
Expand Down Expand Up @@ -54,24 +50,16 @@ pub fn futex<'tcx>(
op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => {
let wait_bitset = op & !futex_realtime == futex_wait_bitset;

let bitset = if wait_bitset {
let [_, _, _, timeout, uaddr2, bitset, ..] = args else {
throw_ub_format!(
"incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6",
args.len()
);
};
let (timeout, bitset) = if wait_bitset {
let [_, _, _, _, timeout, uaddr2, bitset] =
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", args)?;
let _timeout = this.read_pointer(timeout)?;
let _uaddr2 = this.read_pointer(uaddr2)?;
this.read_scalar(bitset)?.to_u32()?
(timeout, this.read_scalar(bitset)?.to_u32()?)
} else {
if args.len() < 4 {
throw_ub_format!(
"incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 4",
args.len()
);
}
u32::MAX
let [_, _, _, _, timeout] =
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", args)?;
(timeout, u32::MAX)
};

if bitset == 0 {
Expand All @@ -80,7 +68,7 @@ pub fn futex<'tcx>(
return interp_ok(());
}

let timeout = this.deref_pointer_as(&args[3], this.libc_ty_layout("timespec"))?;
let timeout = this.deref_pointer_as(timeout, this.libc_ty_layout("timespec"))?;
let timeout = if this.ptr_is_null(timeout.ptr())? {
None
} else {
Expand Down Expand Up @@ -183,12 +171,8 @@ pub fn futex<'tcx>(
// Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
op if op == futex_wake || op == futex_wake_bitset => {
let bitset = if op == futex_wake_bitset {
let [_, _, _, timeout, uaddr2, bitset, ..] = args else {
throw_ub_format!(
"incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6",
args.len()
);
};
let [_, _, _, _, timeout, uaddr2, bitset] =
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?;
let _timeout = this.read_pointer(timeout)?;
let _uaddr2 = this.read_pointer(uaddr2)?;
this.read_scalar(bitset)?.to_u32()?
Expand Down