Skip to content

Commit f3a76a1

Browse files
committed
keep around some information for dead allocations so that we can use it to make sure a dangling ptr aligned and non-NULL
1 parent 7896af9 commit f3a76a1

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

src/librustc_mir/interpret/memory.rs

+46-5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
5151
/// a static creates a copy here, in the machine.
5252
alloc_map: FxHashMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
5353

54+
/// To be able to compare pointers with NULL, and to check alignment for accesses
55+
/// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
56+
/// that do not exist any more.
57+
dead_alloc_map: FxHashMap<AllocId, (Size, Align)>,
58+
5459
pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
5560
}
5661

@@ -74,6 +79,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
7479
Memory {
7580
data,
7681
alloc_map: FxHashMap::default(),
82+
dead_alloc_map: FxHashMap::default(),
7783
tcx,
7884
}
7985
}
@@ -150,6 +156,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
150156
size_and_align: Option<(Size, Align)>,
151157
kind: MemoryKind<M::MemoryKinds>,
152158
) -> EvalResult<'tcx> {
159+
debug!("deallocating: {}", ptr.alloc_id);
160+
153161
if ptr.offset.bytes() != 0 {
154162
return err!(DeallocateNonBasePtr);
155163
}
@@ -189,23 +197,41 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
189197
}
190198
}
191199

192-
debug!("deallocated : {}", ptr.alloc_id);
200+
// Don't forget to remember size and align of this now-dead allocation
201+
let old = self.dead_alloc_map.insert(
202+
ptr.alloc_id,
203+
(Size::from_bytes(alloc.bytes.len() as u64), alloc.align)
204+
);
205+
if old.is_some() {
206+
bug!("Nothing can be deallocated twice");
207+
}
193208

194209
Ok(())
195210
}
196211

197-
/// Check that the pointer is aligned AND non-NULL. This supports scalars
198-
/// for the benefit of other parts of miri that need to check alignment even for ZST.
212+
/// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
213+
/// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
199214
pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
200215
// Check non-NULL/Undef, extract offset
201216
let (offset, alloc_align) = match ptr {
202217
Scalar::Ptr(ptr) => {
203-
let alloc = self.get(ptr.alloc_id)?;
204-
(ptr.offset.bytes(), alloc.align)
218+
let (size, align) = self.get_size_and_align(ptr.alloc_id)?;
219+
// check this is not NULL -- which we can ensure only if this is in-bounds
220+
// of some (potentially dead) allocation.
221+
if ptr.offset > size {
222+
return err!(PointerOutOfBounds {
223+
ptr,
224+
access: true,
225+
allocation_size: size,
226+
});
227+
};
228+
// keep data for alignment check
229+
(ptr.offset.bytes(), align)
205230
}
206231
Scalar::Bits { bits, size } => {
207232
assert_eq!(size as u64, self.pointer_size().bytes());
208233
assert!(bits < (1u128 << self.pointer_size().bits()));
234+
// check this is not NULL
209235
if bits == 0 {
210236
return err!(InvalidNullPointerUsage);
211237
}
@@ -306,6 +332,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
306332
}
307333
}
308334

335+
pub fn get_size_and_align(&self, id: AllocId) -> EvalResult<'tcx, (Size, Align)> {
336+
Ok(match self.get(id) {
337+
Ok(alloc) => (Size::from_bytes(alloc.bytes.len() as u64), alloc.align),
338+
Err(err) => match err.kind {
339+
EvalErrorKind::DanglingPointerDeref =>
340+
// This should be in the dead allocation map
341+
*self.dead_alloc_map.get(&id).expect(
342+
"allocation missing in dead_alloc_map"
343+
),
344+
// E.g. a function ptr allocation
345+
_ => return Err(err)
346+
}
347+
})
348+
}
349+
309350
pub fn get_mut(
310351
&mut self,
311352
id: AllocId,

src/librustc_mir/interpret/operand.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
219219
}
220220
let (ptr, ptr_align) = mplace.to_scalar_ptr_align();
221221

222-
if mplace.layout.size.bytes() == 0 {
222+
if mplace.layout.is_zst() {
223223
// Not all ZSTs have a layout we would handle below, so just short-circuit them
224224
// all here.
225225
self.memory.check_align(ptr, ptr_align)?;
@@ -376,14 +376,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
376376
})
377377
}
378378

379-
// Take an operand, representing a pointer, and dereference it -- that
379+
// Take an operand, representing a pointer, and dereference it to a place -- that
380380
// will always be a MemPlace.
381381
pub(super) fn deref_operand(
382382
&self,
383383
src: OpTy<'tcx>,
384384
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
385385
let val = self.read_value(src)?;
386-
trace!("deref to {} on {:?}", val.layout.ty, val);
386+
trace!("deref to {} on {:?}", val.layout.ty, *val);
387387
Ok(self.ref_to_mplace(val)?)
388388
}
389389

src/librustc_mir/interpret/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
612612
// wrong type.
613613

614614
// Nothing to do for ZSTs, other than checking alignment
615-
if dest.layout.size.bytes() == 0 {
615+
if dest.layout.is_zst() {
616616
self.memory.check_align(ptr, ptr_align)?;
617617
return Ok(());
618618
}

0 commit comments

Comments
 (0)