Skip to content

Commit

Permalink
Rollup merge of rust-lang#56985 - oli-obk:const_check_bounds, r=RalfJung
Browse files Browse the repository at this point in the history
Allow testing pointers for inboundedness while forbidding dangling pointers

r? @RalfJung
  • Loading branch information
Centril authored Dec 24, 2018
2 parents 05f3b3c + c8bcac5 commit 51f90a1
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 19 deletions.
42 changes: 25 additions & 17 deletions src/librustc_mir/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
Scalar::Ptr(ptr) => {
// check this is not NULL -- which we can ensure only if this is in-bounds
// of some (potentially dead) allocation.
let align = self.check_bounds_ptr_maybe_dead(ptr)?;
let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?;
(ptr.offset.bytes(), align)
}
Scalar::Bits { bits, size } => {
Expand Down Expand Up @@ -297,17 +297,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
/// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
/// of an allocation (i.e., at the first *inaccessible* location) *is* considered
/// in-bounds! This follows C's/LLVM's rules.
/// This function also works for deallocated allocations.
/// Use `.get(ptr.alloc_id)?.check_bounds_ptr(ptr)` if you want to force the allocation
/// to still be live.
/// If you want to check bounds before doing a memory access, better first obtain
/// an `Allocation` and call `check_bounds`.
pub fn check_bounds_ptr_maybe_dead(
pub fn check_bounds_ptr(
&self,
ptr: Pointer<M::PointerTag>,
liveness: InboundsCheck,
) -> EvalResult<'tcx, Align> {
let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id);
ptr.check_in_alloc(allocation_size, InboundsCheck::MaybeDead)?;
let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id, liveness)?;
ptr.check_in_alloc(allocation_size, liveness)?;
Ok(align)
}
}
Expand Down Expand Up @@ -429,27 +427,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
}
}

pub fn get_size_and_align(&self, id: AllocId) -> (Size, Align) {
/// Obtain the size and alignment of an allocation, even if that allocation has been deallocated
///
/// If `liveness` is `InboundsCheck::Dead`, this function always returns `Ok`
pub fn get_size_and_align(
&self,
id: AllocId,
liveness: InboundsCheck,
) -> EvalResult<'static, (Size, Align)> {
if let Ok(alloc) = self.get(id) {
return (Size::from_bytes(alloc.bytes.len() as u64), alloc.align);
return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
}
// Could also be a fn ptr or extern static
match self.tcx.alloc_map.lock().get(id) {
Some(AllocKind::Function(..)) => (Size::ZERO, Align::from_bytes(1).unwrap()),
Some(AllocKind::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())),
Some(AllocKind::Static(did)) => {
// The only way `get` couldn't have worked here is if this is an extern static
assert!(self.tcx.is_foreign_item(did));
// Use size and align of the type
let ty = self.tcx.type_of(did);
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
(layout.size, layout.align.abi)
}
_ => {
// Must be a deallocated pointer
*self.dead_alloc_map.get(&id).expect(
"allocation missing in dead_alloc_map"
)
Ok((layout.size, layout.align.abi))
}
_ => match liveness {
InboundsCheck::MaybeDead => {
// Must be a deallocated pointer
Ok(*self.dead_alloc_map.get(&id).expect(
"allocation missing in dead_alloc_map"
))
},
InboundsCheck::Live => err!(DanglingPointerDeref),
},
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc::mir;
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};

use rustc::mir::interpret::{
GlobalId, AllocId,
GlobalId, AllocId, InboundsCheck,
ConstValue, Pointer, Scalar,
EvalResult, EvalErrorKind,
};
Expand Down Expand Up @@ -647,7 +647,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
// The niche must be just 0 (which an inbounds pointer value never is)
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
self.memory.check_bounds_ptr_maybe_dead(ptr).is_ok();
self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
if !ptr_valid {
return err!(InvalidDiscriminant(raw_discr.erase_tag()));
}
Expand Down

0 comments on commit 51f90a1

Please sign in to comment.