Skip to content

Commit

Permalink
deref shim arguments with actual ty instead of declared ty
Browse files Browse the repository at this point in the history
  • Loading branch information
beepster4096 committed Nov 16, 2022
1 parent 4cc347e commit 7ab34da
Show file tree
Hide file tree
Showing 16 changed files with 234 additions and 144 deletions.
6 changes: 5 additions & 1 deletion src/concurrency/init_once.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::VecDeque;
use std::num::NonZeroU32;

use rustc_index::vec::Idx;
use rustc_middle::ty::layout::TyAndLayout;

use super::sync::EvalContextExtPriv as _;
use super::thread::MachineCallback;
Expand Down Expand Up @@ -94,10 +95,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn init_once_get_or_create_id(
&mut self,
lock_op: &OpTy<'tcx, Provenance>,
lock_layout: TyAndLayout<'tcx>,
offset: u64,
) -> InterpResult<'tcx, InitOnceId> {
let this = self.eval_context_mut();
this.init_once_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
this.init_once_get_or_create(|ecx, next_id| {
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
})
}

/// Provides the closure with the next InitOnceId. Creates that InitOnce if the closure returns None,
Expand Down
19 changes: 15 additions & 4 deletions src/concurrency/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use log::trace;

use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ty::layout::TyAndLayout;

use super::init_once::InitOnce;
use super::vector_clock::VClock;
Expand Down Expand Up @@ -200,11 +201,12 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
&mut self,
next_id: Id,
lock_op: &OpTy<'tcx, Provenance>,
lock_layout: TyAndLayout<'tcx>,
offset: u64,
) -> InterpResult<'tcx, Option<Id>> {
let this = self.eval_context_mut();
let value_place =
this.deref_operand_and_offset(lock_op, offset, this.machine.layouts.u32)?;
this.deref_operand_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;

// Since we are lazy, this update has to be atomic.
let (old, success) = this
Expand Down Expand Up @@ -278,28 +280,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn mutex_get_or_create_id(
&mut self,
lock_op: &OpTy<'tcx, Provenance>,
lock_layout: TyAndLayout<'tcx>,
offset: u64,
) -> InterpResult<'tcx, MutexId> {
let this = self.eval_context_mut();
this.mutex_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
this.mutex_get_or_create(|ecx, next_id| {
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
})
}

fn rwlock_get_or_create_id(
&mut self,
lock_op: &OpTy<'tcx, Provenance>,
lock_layout: TyAndLayout<'tcx>,
offset: u64,
) -> InterpResult<'tcx, RwLockId> {
let this = self.eval_context_mut();
this.rwlock_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
this.rwlock_get_or_create(|ecx, next_id| {
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
})
}

fn condvar_get_or_create_id(
&mut self,
lock_op: &OpTy<'tcx, Provenance>,
lock_layout: TyAndLayout<'tcx>,
offset: u64,
) -> InterpResult<'tcx, CondvarId> {
let this = self.eval_context_mut();
this.condvar_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
this.condvar_get_or_create(|ecx, next_id| {
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
})
}

#[inline]
Expand Down
35 changes: 27 additions & 8 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,31 +664,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
}

/// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
fn deref_operand_as(
&self,
op: &OpTy<'tcx, Provenance>,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_ref();
let ptr = this.read_pointer(op)?;

let mplace = MPlaceTy::from_aligned_ptr(ptr, layout);

this.check_mplace(mplace)?;

Ok(mplace)
}

/// Calculates the MPlaceTy given the offset and layout of an access on an operand
fn deref_operand_and_offset(
&self,
op: &OpTy<'tcx, Provenance>,
offset: u64,
layout: TyAndLayout<'tcx>,
base_layout: TyAndLayout<'tcx>,
value_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_ref();
let op_place = this.deref_operand(op)?; // FIXME: we still deref with the original type!
let op_place = this.deref_operand_as(op, base_layout)?;
let offset = Size::from_bytes(offset);

// Ensure that the access is within bounds.
assert!(op_place.layout.size >= offset + layout.size);
let value_place = op_place.offset(offset, layout, this)?;
assert!(base_layout.size >= offset + value_layout.size);
let value_place = op_place.offset(offset, value_layout, this)?;
Ok(value_place)
}

fn read_scalar_at_offset(
&self,
op: &OpTy<'tcx, Provenance>,
offset: u64,
layout: TyAndLayout<'tcx>,
base_layout: TyAndLayout<'tcx>,
value_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
this.read_scalar(&value_place.into())
}

Expand All @@ -697,10 +715,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
op: &OpTy<'tcx, Provenance>,
offset: u64,
value: impl Into<Scalar<Provenance>>,
layout: TyAndLayout<'tcx>,
base_layout: TyAndLayout<'tcx>,
value_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
this.write_scalar(value, &value_place.into())
}

Expand Down
2 changes: 1 addition & 1 deletion src/shims/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// // First thing: load all the arguments. Details depend on the shim.
// let arg1 = this.read_scalar(arg1)?.to_u32()?;
// let arg2 = this.read_pointer(arg2)?; // when you need to work with the pointer directly
// let arg3 = this.deref_operand(arg3)?; // when you want to load/store through the pointer at its declared type
// let arg3 = this.deref_operand_as(arg3, this.machine.layouts.u64)?; // when you want to load/store through the pointer
//
// // ...
//
Expand Down
24 changes: 14 additions & 10 deletions src/shims/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os("linux", "clock_gettime");

let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
let tp = this.deref_operand_as(tp_op, this.libc_ty_layout("timespec")?)?;

// Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
// Unix epoch, including effects which may cause time to move backwards such as NTP.
Expand Down Expand Up @@ -52,7 +53,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let tv_sec = duration.as_secs();
let tv_nsec = duration.subsec_nanos();

this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?;
this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?;

Ok(Scalar::from_i32(0))
}
Expand All @@ -67,6 +68,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os_is_unix("gettimeofday");
this.check_no_isolation("`gettimeofday`")?;

let tv = this.deref_operand_as(tv_op, this.libc_ty_layout("timeval")?)?;

// Using tz is obsolete and should always be null
let tz = this.read_pointer(tz_op)?;
if !this.ptr_is_null(tz)? {
Expand All @@ -79,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let tv_sec = duration.as_secs();
let tv_usec = duration.subsec_micros();

this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &this.deref_operand(tv_op)?)?;
this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;

Ok(0)
}
Expand All @@ -94,6 +97,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os("windows", "GetSystemTimeAsFileTime");
this.check_no_isolation("`GetSystemTimeAsFileTime`")?;

let filetime = this.deref_operand_as(LPFILETIME_op, this.windows_ty_layout("FILETIME")?)?;

let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
Expand All @@ -107,10 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
this.write_int_fields(
&[dwLowDateTime.into(), dwHighDateTime.into()],
&this.deref_operand(LPFILETIME_op)?,
)?;
this.write_int_fields(&[dwLowDateTime.into(), dwHighDateTime.into()], &filetime)?;

Ok(())
}
Expand All @@ -132,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
})?;
this.write_scalar(
Scalar::from_i64(qpc),
&this.deref_operand(lpPerformanceCount_op)?.into(),
&this.deref_operand_as(lpPerformanceCount_op, this.machine.layouts.u64)?.into(),
)?;
Ok(Scalar::from_i32(-1)) // return non-zero on success
}
Expand All @@ -153,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// and thus 10^9 counts per second.
this.write_scalar(
Scalar::from_i64(1_000_000_000),
&this.deref_operand(lpFrequency_op)?.into(),
&this.deref_operand_as(lpFrequency_op, this.machine.layouts.u64)?.into(),
)?;
Ok(Scalar::from_i32(-1)) // Return non-zero on success
}
Expand All @@ -180,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

this.assert_target_os("macos", "mach_timebase_info");

let info = this.deref_operand(info_op)?;
let info = this.deref_operand_as(info_op, this.libc_ty_layout("mach_timebase_info")?)?;

// Since our emulated ticks in `mach_absolute_time` *are* nanoseconds,
// no scaling needs to happen.
Expand All @@ -199,7 +201,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

this.assert_target_os_is_unix("nanosleep");

let duration = match this.read_timespec(&this.deref_operand(req_op)?)? {
let req = this.deref_operand_as(req_op, this.libc_ty_layout("timespec")?)?;

let duration = match this.read_timespec(&req)? {
Some(duration) => duration,
None => {
let einval = this.eval_libc("EINVAL")?;
Expand Down
16 changes: 8 additions & 8 deletions src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Allocation
"posix_memalign" => {
let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ret = this.deref_operand(ret)?;
let ret = this.deref_operand_as(ret, this.machine.layouts.mut_raw_ptr)?;
let align = this.read_scalar(align)?.to_machine_usize(this)?;
let size = this.read_scalar(size)?.to_machine_usize(this)?;
// Align must be power of 2, and also at least ptr-sized (POSIX rules).
Expand Down Expand Up @@ -253,7 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Thread-local storage
"pthread_key_create" => {
let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let key_place = this.deref_operand(key)?;
let key_place = this.deref_operand_as(key, this.libc_ty_layout("pthread_key_t")?)?;
let dtor = this.read_pointer(dtor)?;

// Extract the function type out of the signature (that seems easier than constructing it ourselves).
Expand Down Expand Up @@ -488,7 +488,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"pthread_attr_getguardsize"
if this.frame_in_std() => {
let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let guard_size = this.deref_operand(guard_size)?;
let guard_size = this.deref_operand_as(guard_size, this.machine.layouts.usize)?;
let guard_size_layout = this.libc_ty_layout("size_t")?;
this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?;

Expand All @@ -514,9 +514,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Hence we can mostly ignore the input `attr_place`.
let [attr_place, addr_place, size_place] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let _attr_place = this.deref_operand(attr_place)?;
let addr_place = this.deref_operand(addr_place)?;
let size_place = this.deref_operand(size_place)?;
let _attr_place = this.deref_operand_as(attr_place, this.libc_ty_layout("pthread_attr_t")?)?;
let addr_place = this.deref_operand_as(addr_place, this.machine.layouts.mut_raw_ptr)?;
let size_place = this.deref_operand_as(size_place, this.machine.layouts.usize)?;

this.write_scalar(
Scalar::from_uint(STACK_ADDR, this.pointer_size()),
Expand Down Expand Up @@ -557,10 +557,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_no_isolation("`getpwuid_r`")?;

let uid = this.read_scalar(uid)?.to_u32()?;
let pwd = this.deref_operand(pwd)?;
let pwd = this.deref_operand_as(pwd, this.libc_ty_layout("passwd")?)?;
let buf = this.read_pointer(buf)?;
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
let result = this.deref_operand(result)?;
let result = this.deref_operand_as(result, this.machine.layouts.mut_raw_ptr)?;

// Must be for "us".
if uid != crate::shims::unix::UID {
Expand Down
31 changes: 10 additions & 21 deletions src/shims/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use std::time::SystemTime;
use log::trace;

use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::{self, layout::LayoutOf};
use rustc_target::abi::{Align, Size};

use crate::shims::os_str::bytes_to_os_str;
Expand Down Expand Up @@ -347,7 +346,8 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx
let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));

let buf = this.deref_operand(buf_op)?;
let buf = this.deref_operand_as(buf_op, this.libc_ty_layout("stat")?)?;

this.write_int_fields_named(
&[
("st_dev", 0),
Expand Down Expand Up @@ -1000,20 +1000,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
return Ok(-1);
}

// Under normal circumstances, we would use `deref_operand(statxbuf_op)` to produce a
// proper `MemPlace` and then write the results of this function to it. However, the
// `syscall` function is untyped. This means that all the `statx` parameters are provided
// as `isize`s instead of having the proper types. Thus, we have to recover the layout of
// `statxbuf_op` by using the `libc::statx` struct type.
let statxbuf = {
// FIXME: This long path is required because `libc::statx` is an struct and also a
// function and `resolve_path` is returning the latter.
let statx_ty = this
.resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])
.ty(*this.tcx, ty::ParamEnv::reveal_all());
let statx_layout = this.layout_of(statx_ty)?;
MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout)
};
let statxbuf = this.deref_operand_as(statxbuf_op, this.libc_ty_layout("statx")?)?;

let path = this.read_path_from_c_str(pathname_ptr)?.into_owned();
// See </~https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
Expand Down Expand Up @@ -1419,7 +1406,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// pub d_name: [c_char; 1024],
// }

let entry_place = this.deref_operand(entry_op)?;
let entry_place =
this.deref_operand_as(entry_op, this.libc_ty_layout("dirent")?)?;
let name_place = this.mplace_field(&entry_place, 5)?;

let file_name = dir_entry.file_name(); // not a Path as there are no separators!
Expand All @@ -1435,8 +1423,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
);
}

let entry_place = this.deref_operand(entry_op)?;

// If the host is a Unix system, fill in the inode number with its real value.
// If not, use 0 as a fallback value.
#[cfg(unix)]
Expand All @@ -1457,14 +1443,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
&entry_place,
)?;

let result_place = this.deref_operand(result_op)?;
let result_place =
this.deref_operand_as(result_op, this.machine.layouts.mut_raw_ptr)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?;

0
}
None => {
// end of stream: return 0, assign *result=NULL
this.write_null(&this.deref_operand(result_op)?.into())?;
this.write_null(
&this.deref_operand_as(result_op, this.machine.layouts.mut_raw_ptr)?.into(),
)?;
0
}
Some(Err(e)) =>
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 @@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.read_scalar(pid)?.to_i32()?;
this.read_scalar(cpusetsize)?.to_machine_usize(this)?;
this.deref_operand(mask)?;
this.deref_operand_as(mask, this.libc_ty_layout("cpu_set_t")?)?;
// FIXME: we just return an error; `num_cpus` then falls back to `sysconf`.
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
Expand Down
Loading

0 comments on commit 7ab34da

Please sign in to comment.