Skip to content

Commit adfede5

Browse files
authored
Merge pull request #526 from RalfJung/mut-visitor
Retagging: Recurse into compound values
2 parents dc2d15d + 5b095e1 commit adfede5

19 files changed

+293
-120
lines changed

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ build: false
3737
test_script:
3838
- set RUSTFLAGS=-g
3939
- set RUST_BACKTRACE=1
40-
- cargo build --release --all-targets --all-features
40+
- cargo build --release --all-features --all-targets
4141
- cargo test --release --all-features
4242
- set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST
4343
- cargo test --release --all-features

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2018-11-16
1+
nightly-2018-11-20

src/fn_call.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
131131
}
132132

133133
"free" => {
134-
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag
134+
let ptr = self.read_scalar(args[0])?.not_undef()?;
135135
if !ptr.is_null_ptr(self) {
136136
self.memory_mut().deallocate(
137-
ptr.to_ptr()?.with_default_tag(),
137+
ptr.to_ptr()?,
138138
None,
139139
MiriMemoryKind::C.into(),
140140
)?;
@@ -179,7 +179,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
179179
self.write_scalar(Scalar::Ptr(ptr), dest)?;
180180
}
181181
"__rust_dealloc" => {
182-
let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag
182+
let ptr = self.read_scalar(args[0])?.to_ptr()?;
183183
let old_size = self.read_scalar(args[1])?.to_usize(self)?;
184184
let align = self.read_scalar(args[2])?.to_usize(self)?;
185185
if old_size == 0 {
@@ -189,13 +189,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
189189
return err!(HeapAllocNonPowerOfTwoAlignment(align));
190190
}
191191
self.memory_mut().deallocate(
192-
ptr.with_default_tag(),
192+
ptr,
193193
Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())),
194194
MiriMemoryKind::Rust.into(),
195195
)?;
196196
}
197197
"__rust_realloc" => {
198-
let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag
198+
let ptr = self.read_scalar(args[0])?.to_ptr()?;
199199
let old_size = self.read_scalar(args[1])?.to_usize(self)?;
200200
let align = self.read_scalar(args[2])?.to_usize(self)?;
201201
let new_size = self.read_scalar(args[3])?.to_usize(self)?;
@@ -206,7 +206,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
206206
return err!(HeapAllocNonPowerOfTwoAlignment(align));
207207
}
208208
let new_ptr = self.memory_mut().reallocate(
209-
ptr.with_default_tag(),
209+
ptr,
210210
Size::from_bytes(old_size),
211211
Align::from_bytes(align, align).unwrap(),
212212
Size::from_bytes(new_size),
@@ -238,8 +238,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
238238

239239
"dlsym" => {
240240
let _handle = self.read_scalar(args[0])?;
241-
let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag();
242-
let symbol_name = self.memory().read_c_str(symbol.with_default_tag())?;
241+
let symbol = self.read_scalar(args[1])?.to_ptr()?;
242+
let symbol_name = self.memory().read_c_str(symbol)?;
243243
let err = format!("bad c unicode symbol: {:?}", symbol_name);
244244
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
245245
return err!(Unimplemented(format!(
@@ -292,13 +292,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
292292
return err!(MachineError("the evaluated program panicked".to_string())),
293293

294294
"memcmp" => {
295-
let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
296-
let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation
295+
let left = self.read_scalar(args[0])?.not_undef()?;
296+
let right = self.read_scalar(args[1])?.not_undef()?;
297297
let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?);
298298

299299
let result = {
300-
let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?;
301-
let right_bytes = self.memory().read_bytes(right.with_default_tag(), n)?;
300+
let left_bytes = self.memory().read_bytes(left, n)?;
301+
let right_bytes = self.memory().read_bytes(right, n)?;
302302

303303
use std::cmp::Ordering::*;
304304
match left_bytes.cmp(right_bytes) {
@@ -315,8 +315,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
315315
}
316316

317317
"memrchr" => {
318-
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
319-
let ptr = ptr.with_default_tag();
318+
let ptr = self.read_scalar(args[0])?.not_undef()?;
320319
let val = self.read_scalar(args[1])?.to_bytes()? as u8;
321320
let num = self.read_scalar(args[2])?.to_usize(self)?;
322321
if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?
@@ -330,8 +329,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
330329
}
331330

332331
"memchr" => {
333-
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
334-
let ptr = ptr.with_default_tag();
332+
let ptr = self.read_scalar(args[0])?.not_undef()?;
335333
let val = self.read_scalar(args[1])?.to_bytes()? as u8;
336334
let num = self.read_scalar(args[2])?.to_usize(self)?;
337335
if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position(
@@ -347,8 +345,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
347345

348346
"getenv" => {
349347
let result = {
350-
let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation
351-
let name = self.memory().read_c_str(name_ptr.with_default_tag())?;
348+
let name_ptr = self.read_scalar(args[0])?.to_ptr()?;
349+
let name = self.memory().read_c_str(name_ptr)?;
352350
match self.machine.env_vars.get(name) {
353351
Some(&var) => Scalar::Ptr(var),
354352
None => Scalar::ptr_null(&*self.tcx),
@@ -360,10 +358,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
360358
"unsetenv" => {
361359
let mut success = None;
362360
{
363-
let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
361+
let name_ptr = self.read_scalar(args[0])?.not_undef()?;
364362
if !name_ptr.is_null_ptr(self) {
365363
let name = self.memory().read_c_str(name_ptr.to_ptr()?
366-
.with_default_tag())?.to_owned();
364+
)?.to_owned();
367365
if !name.is_empty() && !name.contains(&b'=') {
368366
success = Some(self.machine.env_vars.remove(&name));
369367
}
@@ -382,11 +380,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
382380
"setenv" => {
383381
let mut new = None;
384382
{
385-
let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
386-
let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation
387-
let value = self.memory().read_c_str(value_ptr.with_default_tag())?;
383+
let name_ptr = self.read_scalar(args[0])?.not_undef()?;
384+
let value_ptr = self.read_scalar(args[1])?.to_ptr()?;
385+
let value = self.memory().read_c_str(value_ptr)?;
388386
if !name_ptr.is_null_ptr(self) {
389-
let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?;
387+
let name = self.memory().read_c_str(name_ptr.to_ptr()?)?;
390388
if !name.is_empty() && !name.contains(&b'=') {
391389
new = Some((name.to_owned(), value.to_owned()));
392390
}
@@ -417,14 +415,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
417415

418416
"write" => {
419417
let fd = self.read_scalar(args[0])?.to_bytes()?;
420-
let buf = self.read_scalar(args[1])?.not_undef()?.erase_tag();
418+
let buf = self.read_scalar(args[1])?.not_undef()?;
421419
let n = self.read_scalar(args[2])?.to_bytes()? as u64;
422420
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
423421
let result = if fd == 1 || fd == 2 {
424422
// stdout/stderr
425423
use std::io::{self, Write};
426424

427-
let buf_cont = self.memory().read_bytes(buf.with_default_tag(), Size::from_bytes(n))?;
425+
let buf_cont = self.memory().read_bytes(buf, Size::from_bytes(n))?;
428426
let res = if fd == 1 {
429427
io::stdout().write(buf_cont)
430428
} else {
@@ -445,8 +443,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
445443
}
446444

447445
"strlen" => {
448-
let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag();
449-
let n = self.memory().read_c_str(ptr.with_default_tag())?.len();
446+
let ptr = self.read_scalar(args[0])?.to_ptr()?;
447+
let n = self.memory().read_c_str(ptr)?.len();
450448
self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
451449
}
452450

@@ -492,7 +490,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
492490

493491
// Hook pthread calls that go to the thread-local storage memory subsystem
494492
"pthread_key_create" => {
495-
let key_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation
493+
let key_ptr = self.read_scalar(args[0])?.to_ptr()?;
496494

497495
// Extract the function type out of the signature (that seems easier than constructing it ourselves...)
498496
let dtor = match self.read_scalar(args[1])?.not_undef()? {
@@ -515,7 +513,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
515513
return err!(OutOfTls);
516514
}
517515
self.memory_mut().write_scalar(
518-
key_ptr.with_default_tag(),
516+
key_ptr,
519517
key_layout.align,
520518
Scalar::from_uint(key, key_layout.size).into(),
521519
key_layout.size,

src/helpers.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
158158
unsafe_cell_action: F,
159159
}
160160

161-
impl<'ecx, 'a, 'mir, 'tcx, F> ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>>
162-
for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F>
161+
impl<'ecx, 'a, 'mir, 'tcx, F>
162+
ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>>
163+
for
164+
UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F>
163165
where
164166
F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>
165167
{
@@ -230,7 +232,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
230232
}
231233

232234
// We should never get to a primitive, but always short-circuit somewhere above
233-
fn visit_primitive(&mut self, _val: ImmTy<'tcx, Borrow>) -> EvalResult<'tcx>
235+
fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>
234236
{
235237
bug!("We should always short-circit before coming to a primitive")
236238
}

src/intrinsic.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
154154
let count = self.read_scalar(args[2])?.to_usize(self)?;
155155
let elem_align = elem_layout.align;
156156
// erase tags: this is a raw ptr operation
157-
let src = self.read_scalar(args[0])?.not_undef()?.erase_tag();
158-
let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag();
157+
let src = self.read_scalar(args[0])?.not_undef()?;
158+
let dest = self.read_scalar(args[1])?.not_undef()?;
159159
self.memory_mut().copy(
160-
src.with_default_tag(),
160+
src,
161161
elem_align,
162-
dest.with_default_tag(),
162+
dest,
163163
elem_align,
164164
Size::from_bytes(count * elem_size),
165165
intrinsic_name.ends_with("_nonoverlapping"),
@@ -436,7 +436,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
436436
let ty = substs.type_at(0);
437437
let ty_layout = self.layout_of(ty)?;
438438
let val_byte = self.read_scalar(args[1])?.to_u8()?;
439-
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag();
439+
let ptr = self.read_scalar(args[0])?.not_undef()?;
440440
let count = self.read_scalar(args[2])?.to_usize(self)?;
441441
self.memory().check_align(ptr, ty_layout.align)?;
442442
self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?;

src/lib.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc::hir::{self, def_id::DefId};
2323
use rustc::mir;
2424

2525
use syntax::attr;
26-
26+
use syntax::source_map::DUMMY_SP;
2727

2828
pub use rustc_mir::interpret::*;
2929
pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity
@@ -113,7 +113,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
113113
// Push our stack frame
114114
ecx.push_stack_frame(
115115
start_instance,
116-
start_mir.span,
116+
DUMMY_SP, // there is no call site, we want no span
117117
start_mir,
118118
Some(ret_ptr.into()),
119119
StackPopCleanup::None { cleanup: true },
@@ -146,7 +146,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
146146
let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into();
147147
ecx.push_stack_frame(
148148
main_instance,
149-
main_mir.span,
149+
DUMMY_SP, // there is no call site, we want no span
150150
main_mir,
151151
Some(ret_place),
152152
StackPopCleanup::None { cleanup: true },
@@ -185,7 +185,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
185185
match res {
186186
Ok(()) => {
187187
let leaks = ecx.memory().leak_report();
188-
// Disable the leak test on some platforms where we likely do not
188+
// Disable the leak test on some platforms where we do not
189189
// correctly implement TLS destructors.
190190
let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
191191
let ignore_leaks = target_os == "windows" || target_os == "macos";
@@ -208,8 +208,16 @@ pub fn eval_main<'a, 'tcx: 'a>(
208208
let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str());
209209
let frames = ecx.generate_stacktrace(None);
210210
err.span_label(span, e);
211-
for FrameInfo { span, location, .. } in frames {
212-
err.span_note(span, &format!("inside call to `{}`", location));
211+
// we iterate with indices because we need to look at the next frame (the caller)
212+
for idx in 0..frames.len() {
213+
let frame_info = &frames[idx];
214+
let call_site_is_local = frames.get(idx+1).map_or(false,
215+
|caller_info| caller_info.instance.def_id().is_local());
216+
if call_site_is_local {
217+
err.span_note(frame_info.call_site, &frame_info.to_string());
218+
} else {
219+
err.note(&frame_info.to_string());
220+
}
213221
}
214222
err.emit();
215223
} else {
@@ -312,8 +320,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
312320
// Uses mem::uninitialized
313321
("std::ptr::read", ""),
314322
("std::sys::windows::mutex::Mutex::", ""),
315-
// Should directly take a raw reference
316-
("<std::cell::UnsafeCell<T>>", "::get"),
317323
];
318324
for frame in ecx.stack().iter()
319325
.rev().take(3)
@@ -461,9 +467,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
461467
// No tracking
462468
Ok(place.ptr)
463469
} else {
464-
let ptr = place.ptr.to_ptr()?; // assert this is not a scalar
465-
let tag = ecx.tag_dereference(place, size, mutability.into())?;
466-
Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)))
470+
ecx.ptr_dereference(place, size, mutability.into())?;
471+
// We never change the pointer
472+
Ok(place.ptr)
467473
}
468474
}
469475

src/operator.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
142142
// allocations sit right next to each other. The C/C++ standards are
143143
// somewhat fuzzy about this case, so I think for now this check is
144144
// "good enough".
145-
self.memory().check_bounds_ptr(left, false)?;
146-
self.memory().check_bounds_ptr(right, false)?;
145+
// We require liveness, as dead allocations can of course overlap.
146+
self.memory().check_bounds_ptr(left, InboundsCheck::Live)?;
147+
self.memory().check_bounds_ptr(right, InboundsCheck::Live)?;
147148
// Two live in-bounds pointers, we can compare across allocations
148149
left == right
149150
}
@@ -153,15 +154,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
153154
(Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => {
154155
assert_eq!(size as u64, self.pointer_size().bytes());
155156
let bits = bits as u64;
156-
let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id);
157157

158158
// Case I: Comparing with NULL
159159
if bits == 0 {
160160
// Test if the ptr is in-bounds. Then it cannot be NULL.
161-
if ptr.offset <= alloc_size {
161+
if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() {
162162
return Ok(false);
163163
}
164164
}
165+
166+
let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id);
167+
165168
// Case II: Alignment gives it away
166169
if ptr.offset.bytes() % alloc_align.abi() == 0 {
167170
// The offset maintains the allocation alignment, so we know `base+offset`
@@ -293,11 +296,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
293296
let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?;
294297
// Now let's see what kind of pointer this is
295298
if let Scalar::Ptr(ptr) = ptr {
296-
// Both old and new pointer must be in-bounds.
299+
// Both old and new pointer must be in-bounds of a *live* allocation.
297300
// (Of the same allocation, but that part is trivial with our representation.)
298-
self.memory().check_bounds_ptr(ptr, false)?;
301+
self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?;
299302
let ptr = ptr.signed_offset(offset, self)?;
300-
self.memory().check_bounds_ptr(ptr, false)?;
303+
self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?;
301304
Ok(Scalar::Ptr(ptr))
302305
} else {
303306
// An integer pointer. They can only be offset by 0, and we pretend there

0 commit comments

Comments
 (0)