Skip to content

Commit 09919c2

Browse files
committed
Retag is the only operation that generates new tags
1 parent 3554d1a commit 09919c2

11 files changed

+161
-102
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ target
22
/doc
33
tex/*/out
44
*.dot
5-
*.mir
65
*.rs.bk
76
Cargo.lock

src/fn_call.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
555555
}
556556
"pthread_attr_getstack" => {
557557
// second argument is where we are supposed to write the stack size
558-
let ptr = self.ref_to_mplace(self.read_immediate(args[1])?)?;
558+
let ptr = self.deref_operand(args[1])?;
559559
let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address
560560
self.write_scalar(stackaddr, ptr.into())?;
561561
// return 0

src/intrinsic.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
5959
"atomic_load_relaxed" |
6060
"atomic_load_acq" |
6161
"volatile_load" => {
62-
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?;
62+
let ptr = self.deref_operand(args[0])?;
6363
let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic
6464
self.write_scalar(val, dest)?;
6565
}
@@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
6868
"atomic_store_relaxed" |
6969
"atomic_store_rel" |
7070
"volatile_store" => {
71-
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?;
71+
let ptr = self.deref_operand(args[0])?;
7272
let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic
7373
self.write_scalar(val, ptr.into())?;
7474
}
@@ -78,18 +78,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
7878
}
7979

8080
_ if intrinsic_name.starts_with("atomic_xchg") => {
81-
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?;
81+
let ptr = self.deref_operand(args[0])?;
8282
let new = self.read_scalar(args[1])?;
8383
let old = self.read_scalar(ptr.into())?;
8484
self.write_scalar(old, dest)?; // old value is returned
8585
self.write_scalar(new, ptr.into())?;
8686
}
8787

8888
_ if intrinsic_name.starts_with("atomic_cxchg") => {
89-
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?;
90-
let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_imm()`
89+
let ptr = self.deref_operand(args[0])?;
90+
let expect_old = self.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()`
9191
let new = self.read_scalar(args[2])?;
92-
let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_imm()`
92+
let old = self.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()`
9393
// binary_op_imm will bail if either of them is not a scalar
9494
let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?;
9595
let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into());
@@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
125125
"atomic_xsub_rel" |
126126
"atomic_xsub_acqrel" |
127127
"atomic_xsub_relaxed" => {
128-
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?;
128+
let ptr = self.deref_operand(args[0])?;
129129
if !ptr.layout.ty.is_integral() {
130130
return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types")));
131131
}
@@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
167167
}
168168

169169
"discriminant_value" => {
170-
let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
170+
let place = self.deref_operand(args[0])?;
171171
let discr_val = self.read_discriminant(place.into())?.0;
172172
self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?;
173173
}
@@ -279,7 +279,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
279279
}
280280

281281
"move_val_init" => {
282-
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?;
282+
let ptr = self.deref_operand(args[0])?;
283283
self.copy_op(args[1], ptr.into())?;
284284
}
285285

@@ -347,7 +347,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
347347
}
348348

349349
"size_of_val" => {
350-
let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?;
350+
let mplace = self.deref_operand(args[0])?;
351351
let (size, _) = self.size_and_align_of_mplace(mplace)?
352352
.expect("size_of_val called on extern type");
353353
let ptr_size = self.pointer_size();
@@ -359,7 +359,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
359359

360360
"min_align_of_val" |
361361
"align_of_val" => {
362-
let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?;
362+
let mplace = self.deref_operand(args[0])?;
363363
let (_, align) = self.size_and_align_of_mplace(mplace)?
364364
.expect("size_of_val called on extern type");
365365
let ptr_size = self.pointer_size();

src/lib.rs

+32-26
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
296296

297297
type AllocExtra = stacked_borrows::Stacks;
298298
type PointerTag = Borrow;
299-
const ENABLE_PTR_TRACKING_HOOKS: bool = true;
300299

301300
type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Borrow, Self::AllocExtra>)>;
302301

@@ -446,26 +445,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
446445
Cow::Owned(alloc)
447446
}
448447

449-
#[inline(always)]
450-
fn tag_reference(
451-
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
452-
place: MPlaceTy<'tcx, Borrow>,
453-
mutability: Option<hir::Mutability>,
454-
) -> EvalResult<'tcx, Scalar<Borrow>> {
455-
let (size, _) = ecx.size_and_align_of_mplace(place)?
456-
// for extern types, just cover what we can
457-
.unwrap_or_else(|| place.layout.size_and_align());
458-
if !ecx.machine.validate || size == Size::ZERO {
459-
// No tracking
460-
Ok(place.ptr)
461-
} else {
462-
let ptr = place.ptr.to_ptr()?;
463-
let tag = ecx.tag_reference(place, size, mutability.into())?;
464-
Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)))
465-
}
466-
}
467-
468-
#[inline(always)]
469448
fn tag_dereference(
470449
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
471450
place: MPlaceTy<'tcx, Borrow>,
@@ -478,7 +457,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
478457
// No tracking
479458
Ok(place.ptr)
480459
} else {
481-
let ptr = place.ptr.to_ptr()?;
460+
let ptr = place.ptr.to_ptr()?; // assert this is not a scalar
482461
let tag = ecx.tag_dereference(place, size, mutability.into())?;
483462
Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)))
484463
}
@@ -499,19 +478,46 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
499478
}
500479
}
501480

481+
#[inline]
482+
fn escape_to_raw(
483+
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
484+
ptr: OpTy<'tcx, Self::PointerTag>,
485+
) -> EvalResult<'tcx> {
486+
// It is tempting to check the type here, but drop glue does EscapeToRaw
487+
// on a raw pointer.
488+
// This is deliberately NOT `deref_operand` as we do not want `tag_dereference`
489+
// to be called! That would kill the original tag if we got a raw ptr.
490+
let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?;
491+
let (size, _) = ecx.size_and_align_of_mplace(place)?
492+
// for extern types, just cover what we can
493+
.unwrap_or_else(|| place.layout.size_and_align());
494+
if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag ||
495+
!ecx.machine.validate || size == Size::ZERO
496+
{
497+
// No tracking, or no retagging. The latter is possible because a dependency of ours
498+
// might be called with different flags than we are, so there are `Retag`
499+
// statements but we do not want to execute them.
500+
Ok(())
501+
} else {
502+
ecx.escape_to_raw(place, size)
503+
}
504+
}
505+
502506
#[inline(always)]
503507
fn retag(
504508
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
505509
fn_entry: bool,
506510
place: PlaceTy<'tcx, Borrow>,
507511
) -> EvalResult<'tcx> {
508512
if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) {
509-
// No tracking, or no retagging. This is possible because a dependency of ours might be
510-
// called with different flags than we are,
513+
// No tracking, or no retagging. The latter is possible because a dependency of ours
514+
// might be called with different flags than we are, so there are `Retag`
515+
// statements but we do not want to execute them.
511516
// Also, honor the whitelist in `enforce_validity` because otherwise we might retag
512517
// uninitialized data.
513-
return Ok(())
518+
Ok(())
519+
} else {
520+
ecx.retag(fn_entry, place)
514521
}
515-
ecx.retag(fn_entry, place)
516522
}
517523
}

src/stacked_borrows.rs

+77-50
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc::hir;
66
use crate::{
77
EvalResult, MiriEvalContext, HelpersEvalContextExt,
88
MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra,
9-
Pointer, PlaceTy, MPlaceTy,
9+
Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy,
1010
};
1111

1212
pub type Timestamp = u64;
@@ -395,13 +395,6 @@ impl<'tcx> Stacks {
395395

396396

397397
pub trait EvalContextExt<'tcx> {
398-
fn tag_reference(
399-
&mut self,
400-
place: MPlaceTy<'tcx, Borrow>,
401-
size: Size,
402-
usage: UsageKind,
403-
) -> EvalResult<'tcx, Borrow>;
404-
405398
fn tag_dereference(
406399
&self,
407400
place: MPlaceTy<'tcx, Borrow>,
@@ -415,47 +408,27 @@ pub trait EvalContextExt<'tcx> {
415408
kind: MemoryKind<MiriMemoryKind>,
416409
) -> Borrow;
417410

411+
/// Retag an indidual pointer, returning the retagged version.
412+
fn retag_ptr(
413+
&mut self,
414+
ptr: ImmTy<'tcx, Borrow>,
415+
mutbl: hir::Mutability,
416+
) -> EvalResult<'tcx, Immediate<Borrow>>;
417+
418418
fn retag(
419419
&mut self,
420420
fn_entry: bool,
421421
place: PlaceTy<'tcx, Borrow>
422422
) -> EvalResult<'tcx>;
423-
}
424423

425-
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
426-
/// Called for place-to-value conversion.
427-
fn tag_reference(
424+
fn escape_to_raw(
428425
&mut self,
429426
place: MPlaceTy<'tcx, Borrow>,
430427
size: Size,
431-
usage: UsageKind,
432-
) -> EvalResult<'tcx, Borrow> {
433-
let ptr = place.ptr.to_ptr()?;
434-
let time = self.machine.stacked_borrows.increment_clock();
435-
let new_bor = match usage {
436-
UsageKind::Write => Borrow::Uniq(time),
437-
UsageKind::Read => Borrow::Shr(Some(time)),
438-
UsageKind::Raw => Borrow::Shr(None),
439-
};
440-
trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}): {:?}",
441-
usage, ptr, place.layout.ty, new_bor);
442-
443-
// Update the stacks. First create the new ref as usual, then maybe freeze stuff.
444-
self.memory().check_bounds(ptr, size, false)?;
445-
let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!");
446-
alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?;
447-
// Maybe freeze stuff
448-
if let Borrow::Shr(Some(bor_t)) = new_bor {
449-
self.visit_frozen(place, size, |frz_ptr, size| {
450-
debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id);
451-
// Be frozen!
452-
alloc.extra.freeze(frz_ptr, size, bor_t)
453-
})?;
454-
}
455-
456-
Ok(new_bor)
457-
}
428+
) -> EvalResult<'tcx>;
429+
}
458430

431+
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
459432
/// Called for value-to-place conversion.
460433
///
461434
/// Note that this does NOT mean that all this memory will actually get accessed/referenced!
@@ -466,9 +439,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
466439
size: Size,
467440
usage: UsageKind,
468441
) -> EvalResult<'tcx, Borrow> {
469-
let ptr = place.ptr.to_ptr()?;
470442
trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})",
471-
usage, ptr, place.layout.ty);
443+
usage, place.ptr, place.layout.ty);
444+
let ptr = place.ptr.to_ptr()?;
472445
// In principle we should not have to do anything here. However, with transmutes involved,
473446
// it can happen that the tag of `ptr` does not actually match `usage`, and we
474447
// should adjust for that.
@@ -551,27 +524,81 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
551524
Borrow::Uniq(time)
552525
}
553526

527+
fn retag_ptr(
528+
&mut self,
529+
val: ImmTy<'tcx, Borrow>,
530+
mutbl: hir::Mutability,
531+
) -> EvalResult<'tcx, Immediate<Borrow>> {
532+
// We want a place for where the ptr *points to*, so we get one.
533+
let place = self.ref_to_mplace(val)?;
534+
let size = self.size_and_align_of_mplace(place)?
535+
.map(|(size, _)| size)
536+
.unwrap_or_else(|| place.layout.size);
537+
if size == Size::ZERO {
538+
// Nothing to do for ZSTs.
539+
return Ok(*val);
540+
}
541+
542+
// Prepare to re-borrow this place.
543+
let ptr = place.ptr.to_ptr()?;
544+
let time = self.machine.stacked_borrows.increment_clock();
545+
let new_bor = match mutbl {
546+
hir::MutMutable => Borrow::Uniq(time),
547+
hir::MutImmutable => Borrow::Shr(Some(time)),
548+
};
549+
trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}",
550+
mutbl, ptr, place.layout.ty, new_bor);
551+
552+
// Update the stacks. First create a new borrow, then maybe freeze stuff.
553+
self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr
554+
let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!");
555+
alloc.extra.use_and_maybe_re_borrow(ptr, size, Some(mutbl).into(), Some(new_bor))?;
556+
// Maybe freeze stuff
557+
if let Borrow::Shr(Some(bor_t)) = new_bor {
558+
self.visit_frozen(place, size, |frz_ptr, size| {
559+
debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id);
560+
// Be frozen!
561+
alloc.extra.freeze(frz_ptr, size, bor_t)
562+
})?;
563+
}
564+
565+
// Compute the new value and return that
566+
let new_ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor));
567+
let new_place = MemPlace { ptr: new_ptr, ..*place };
568+
Ok(new_place.to_ref())
569+
}
570+
554571
fn retag(
555572
&mut self,
556573
_fn_entry: bool,
557574
place: PlaceTy<'tcx, Borrow>
558575
) -> EvalResult<'tcx> {
559576
// For now, we only retag if the toplevel type is a reference.
560577
// TODO: Recurse into structs and enums, sharing code with validation.
578+
// TODO: Honor `fn_entry`.
561579
let mutbl = match place.layout.ty.sty {
562580
ty::Ref(_, _, mutbl) => mutbl, // go ahead
563-
_ => return Ok(()), // don't do a thing
581+
_ => return Ok(()), // do nothing, for now
564582
};
565-
// We want to reborrow the reference stored there. This will call the hooks
566-
// above. First deref, which will call `tag_dereference`.
567-
// (This is somewhat redundant because validation already did the same thing,
568-
// but what can you do.)
583+
// Retag the pointer and write it back.
569584
let val = self.read_immediate(self.place_to_op(place)?)?;
570-
let dest = self.ref_to_mplace(val)?;
571-
// Now put a new ref into the old place, which will call `tag_reference`.
572-
// FIXME: Honor `fn_entry`!
573-
let val = self.create_ref(dest, Some(mutbl))?;
585+
let val = self.retag_ptr(val, mutbl)?;
574586
self.write_immediate(val, place)?;
575587
Ok(())
576588
}
589+
590+
fn escape_to_raw(
591+
&mut self,
592+
place: MPlaceTy<'tcx, Borrow>,
593+
size: Size,
594+
) -> EvalResult<'tcx> {
595+
trace!("self: {:?} is now accessible by raw pointers", *place);
596+
// Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow
597+
// type here and that's also okay.
598+
let ptr = place.ptr.to_ptr()?;
599+
self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr
600+
let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!");
601+
alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Raw, Some(Borrow::default()))?;
602+
Ok(())
603+
}
577604
}

0 commit comments

Comments
 (0)