Skip to content

Commit a7e333f

Browse files
committed
deref shim arguments with actual ty instead of declared ty
1 parent 191ab33 commit a7e333f

File tree

16 files changed

+234
-144
lines changed

16 files changed

+234
-144
lines changed

src/concurrency/init_once.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::VecDeque;
22
use std::num::NonZeroU32;
33

44
use rustc_index::vec::Idx;
5+
use rustc_middle::ty::layout::TyAndLayout;
56

67
use super::sync::EvalContextExtPriv as _;
78
use super::thread::MachineCallback;
@@ -94,10 +95,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
9495
fn init_once_get_or_create_id(
9596
&mut self,
9697
lock_op: &OpTy<'tcx, Provenance>,
98+
lock_layout: TyAndLayout<'tcx>,
9799
offset: u64,
98100
) -> InterpResult<'tcx, InitOnceId> {
99101
let this = self.eval_context_mut();
100-
this.init_once_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
102+
this.init_once_get_or_create(|ecx, next_id| {
103+
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
104+
})
101105
}
102106

103107
/// Provides the closure with the next InitOnceId. Creates that InitOnce if the closure returns None,

src/concurrency/sync.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use log::trace;
66

77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_index::vec::{Idx, IndexVec};
9+
use rustc_middle::ty::layout::TyAndLayout;
910

1011
use super::init_once::InitOnce;
1112
use super::vector_clock::VClock;
@@ -200,11 +201,12 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
200201
&mut self,
201202
next_id: Id,
202203
lock_op: &OpTy<'tcx, Provenance>,
204+
lock_layout: TyAndLayout<'tcx>,
203205
offset: u64,
204206
) -> InterpResult<'tcx, Option<Id>> {
205207
let this = self.eval_context_mut();
206208
let value_place =
207-
this.deref_operand_and_offset(lock_op, offset, this.machine.layouts.u32)?;
209+
this.deref_operand_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
208210

209211
// Since we are lazy, this update has to be atomic.
210212
let (old, success) = this
@@ -278,28 +280,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
278280
fn mutex_get_or_create_id(
279281
&mut self,
280282
lock_op: &OpTy<'tcx, Provenance>,
283+
lock_layout: TyAndLayout<'tcx>,
281284
offset: u64,
282285
) -> InterpResult<'tcx, MutexId> {
283286
let this = self.eval_context_mut();
284-
this.mutex_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
287+
this.mutex_get_or_create(|ecx, next_id| {
288+
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
289+
})
285290
}
286291

287292
fn rwlock_get_or_create_id(
288293
&mut self,
289294
lock_op: &OpTy<'tcx, Provenance>,
295+
lock_layout: TyAndLayout<'tcx>,
290296
offset: u64,
291297
) -> InterpResult<'tcx, RwLockId> {
292298
let this = self.eval_context_mut();
293-
this.rwlock_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
299+
this.rwlock_get_or_create(|ecx, next_id| {
300+
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
301+
})
294302
}
295303

296304
fn condvar_get_or_create_id(
297305
&mut self,
298306
lock_op: &OpTy<'tcx, Provenance>,
307+
lock_layout: TyAndLayout<'tcx>,
299308
offset: u64,
300309
) -> InterpResult<'tcx, CondvarId> {
301310
let this = self.eval_context_mut();
302-
this.condvar_get_or_create(|ecx, next_id| ecx.get_or_create_id(next_id, lock_op, offset))
311+
this.condvar_get_or_create(|ecx, next_id| {
312+
ecx.get_or_create_id(next_id, lock_op, lock_layout, offset)
313+
})
303314
}
304315

305316
#[inline]

src/helpers.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -665,31 +665,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
665665
}
666666
}
667667

668+
/// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
669+
fn deref_operand_as(
670+
&self,
671+
op: &OpTy<'tcx, Provenance>,
672+
layout: TyAndLayout<'tcx>,
673+
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
674+
let this = self.eval_context_ref();
675+
let ptr = this.read_pointer(op)?;
676+
677+
let mplace = MPlaceTy::from_aligned_ptr(ptr, layout);
678+
679+
this.check_mplace(mplace)?;
680+
681+
Ok(mplace)
682+
}
683+
668684
/// Calculates the MPlaceTy given the offset and layout of an access on an operand
669685
fn deref_operand_and_offset(
670686
&self,
671687
op: &OpTy<'tcx, Provenance>,
672688
offset: u64,
673-
layout: TyAndLayout<'tcx>,
689+
base_layout: TyAndLayout<'tcx>,
690+
value_layout: TyAndLayout<'tcx>,
674691
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
675692
let this = self.eval_context_ref();
676-
let op_place = this.deref_operand(op)?; // FIXME: we still deref with the original type!
693+
let op_place = this.deref_operand_as(op, base_layout)?;
677694
let offset = Size::from_bytes(offset);
678695

679696
// Ensure that the access is within bounds.
680-
assert!(op_place.layout.size >= offset + layout.size);
681-
let value_place = op_place.offset(offset, layout, this)?;
697+
assert!(base_layout.size >= offset + value_layout.size);
698+
let value_place = op_place.offset(offset, value_layout, this)?;
682699
Ok(value_place)
683700
}
684701

685702
fn read_scalar_at_offset(
686703
&self,
687704
op: &OpTy<'tcx, Provenance>,
688705
offset: u64,
689-
layout: TyAndLayout<'tcx>,
706+
base_layout: TyAndLayout<'tcx>,
707+
value_layout: TyAndLayout<'tcx>,
690708
) -> InterpResult<'tcx, Scalar<Provenance>> {
691709
let this = self.eval_context_ref();
692-
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
710+
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
693711
this.read_scalar(&value_place.into())
694712
}
695713

@@ -698,10 +716,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
698716
op: &OpTy<'tcx, Provenance>,
699717
offset: u64,
700718
value: impl Into<Scalar<Provenance>>,
701-
layout: TyAndLayout<'tcx>,
719+
base_layout: TyAndLayout<'tcx>,
720+
value_layout: TyAndLayout<'tcx>,
702721
) -> InterpResult<'tcx, ()> {
703722
let this = self.eval_context_mut();
704-
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
723+
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
705724
this.write_scalar(value, &value_place.into())
706725
}
707726

src/shims/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
403403
// // First thing: load all the arguments. Details depend on the shim.
404404
// let arg1 = this.read_scalar(arg1)?.to_u32()?;
405405
// let arg2 = this.read_pointer(arg2)?; // when you need to work with the pointer directly
406-
// let arg3 = this.deref_operand(arg3)?; // when you want to load/store through the pointer at its declared type
406+
// let arg3 = this.deref_operand_as(arg3, this.machine.layouts.u64)?; // when you want to load/store through the pointer
407407
//
408408
// // ...
409409
//

src/shims/time.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2525
this.assert_target_os("linux", "clock_gettime");
2626

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

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

55-
this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?;
56+
this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?;
5657

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

71+
let tv = this.deref_operand_as(tv_op, this.libc_ty_layout("timeval")?)?;
72+
7073
// Using tz is obsolete and should always be null
7174
let tz = this.read_pointer(tz_op)?;
7275
if !this.ptr_is_null(tz)? {
@@ -79,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7982
let tv_sec = duration.as_secs();
8083
let tv_usec = duration.subsec_micros();
8184

82-
this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &this.deref_operand(tv_op)?)?;
85+
this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;
8386

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

100+
let filetime = this.deref_operand_as(LPFILETIME_op, this.windows_ty_layout("FILETIME")?)?;
101+
97102
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
98103
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
99104
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
@@ -107,10 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
107112

108113
let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
109114
let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
110-
this.write_int_fields(
111-
&[dwLowDateTime.into(), dwHighDateTime.into()],
112-
&this.deref_operand(LPFILETIME_op)?,
113-
)?;
115+
this.write_int_fields(&[dwLowDateTime.into(), dwHighDateTime.into()], &filetime)?;
114116

115117
Ok(())
116118
}
@@ -132,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
132134
})?;
133135
this.write_scalar(
134136
Scalar::from_i64(qpc),
135-
&this.deref_operand(lpPerformanceCount_op)?.into(),
137+
&this.deref_operand_as(lpPerformanceCount_op, this.machine.layouts.u64)?.into(),
136138
)?;
137139
Ok(Scalar::from_i32(-1)) // return non-zero on success
138140
}
@@ -153,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
153155
// and thus 10^9 counts per second.
154156
this.write_scalar(
155157
Scalar::from_i64(1_000_000_000),
156-
&this.deref_operand(lpFrequency_op)?.into(),
158+
&this.deref_operand_as(lpFrequency_op, this.machine.layouts.u64)?.into(),
157159
)?;
158160
Ok(Scalar::from_i32(-1)) // Return non-zero on success
159161
}
@@ -180,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
180182

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

183-
let info = this.deref_operand(info_op)?;
185+
let info = this.deref_operand_as(info_op, this.libc_ty_layout("mach_timebase_info")?)?;
184186

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

200202
this.assert_target_os_is_unix("nanosleep");
201203

202-
let duration = match this.read_timespec(&this.deref_operand(req_op)?)? {
204+
let req = this.deref_operand_as(req_op, this.libc_ty_layout("timespec")?)?;
205+
206+
let duration = match this.read_timespec(&req)? {
203207
Some(duration) => duration,
204208
None => {
205209
let einval = this.eval_libc("EINVAL")?;

src/shims/unix/foreign_items.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
184184
// Allocation
185185
"posix_memalign" => {
186186
let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
187-
let ret = this.deref_operand(ret)?;
187+
let ret = this.deref_operand_as(ret, this.machine.layouts.mut_raw_ptr)?;
188188
let align = this.read_scalar(align)?.to_machine_usize(this)?;
189189
let size = this.read_scalar(size)?.to_machine_usize(this)?;
190190
// Align must be power of 2, and also at least ptr-sized (POSIX rules).
@@ -253,7 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
253253
// Thread-local storage
254254
"pthread_key_create" => {
255255
let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
256-
let key_place = this.deref_operand(key)?;
256+
let key_place = this.deref_operand_as(key, this.libc_ty_layout("pthread_key_t")?)?;
257257
let dtor = this.read_pointer(dtor)?;
258258

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

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

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

559559
let uid = this.read_scalar(uid)?.to_u32()?;
560-
let pwd = this.deref_operand(pwd)?;
560+
let pwd = this.deref_operand_as(pwd, this.libc_ty_layout("passwd")?)?;
561561
let buf = this.read_pointer(buf)?;
562562
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
563-
let result = this.deref_operand(result)?;
563+
let result = this.deref_operand_as(result, this.machine.layouts.mut_raw_ptr)?;
564564

565565
// Must be for "us".
566566
if uid != crate::shims::unix::UID {

src/shims/unix/fs.rs

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use std::time::SystemTime;
1111
use log::trace;
1212

1313
use rustc_data_structures::fx::FxHashMap;
14-
use rustc_middle::ty::{self, layout::LayoutOf};
1514
use rustc_target::abi::{Align, Size};
1615

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

350-
let buf = this.deref_operand(buf_op)?;
349+
let buf = this.deref_operand_as(buf_op, this.libc_ty_layout("stat")?)?;
350+
351351
this.write_int_fields_named(
352352
&[
353353
("st_dev", 0),
@@ -1000,20 +1000,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10001000
return Ok(-1);
10011001
}
10021002

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

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

1422-
let entry_place = this.deref_operand(entry_op)?;
1409+
let entry_place =
1410+
this.deref_operand_as(entry_op, this.libc_ty_layout("dirent")?)?;
14231411
let name_place = this.mplace_field(&entry_place, 5)?;
14241412

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

1438-
let entry_place = this.deref_operand(entry_op)?;
1439-
14401426
// If the host is a Unix system, fill in the inode number with its real value.
14411427
// If not, use 0 as a fallback value.
14421428
#[cfg(unix)]
@@ -1457,14 +1443,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
14571443
&entry_place,
14581444
)?;
14591445

1460-
let result_place = this.deref_operand(result_op)?;
1446+
let result_place =
1447+
this.deref_operand_as(result_op, this.machine.layouts.mut_raw_ptr)?;
14611448
this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?;
14621449

14631450
0
14641451
}
14651452
None => {
14661453
// end of stream: return 0, assign *result=NULL
1467-
this.write_null(&this.deref_operand(result_op)?.into())?;
1454+
this.write_null(
1455+
&this.deref_operand_as(result_op, this.machine.layouts.mut_raw_ptr)?.into(),
1456+
)?;
14681457
0
14691458
}
14701459
Some(Err(e)) =>

src/shims/unix/linux/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
157157
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
158158
this.read_scalar(pid)?.to_i32()?;
159159
this.read_scalar(cpusetsize)?.to_machine_usize(this)?;
160-
this.deref_operand(mask)?;
160+
this.deref_operand_as(mask, this.libc_ty_layout("cpu_set_t")?)?;
161161
// FIXME: we just return an error; `num_cpus` then falls back to `sysconf`.
162162
let einval = this.eval_libc("EINVAL")?;
163163
this.set_last_error(einval)?;

0 commit comments

Comments
 (0)