Skip to content

Commit 1a1d741

Browse files
authored
Merge pull request rust-lang#203 from RalfJung/offset
Allow any offset on integer and ZST pointers
2 parents 8de1110 + c1a6df9 commit 1a1d741

File tree

4 files changed

+27
-18
lines changed

4 files changed

+27
-18
lines changed

src/error.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub enum EvalError<'tcx> {
2121
access: bool,
2222
allocation_size: u64,
2323
},
24+
NullPointerOutOfBounds,
2425
ReadPointerAsBytes,
2526
ReadBytesAsPointer,
2627
InvalidPointerMath,
@@ -80,12 +81,14 @@ impl<'tcx> Error for EvalError<'tcx> {
8081
"invalid enum discriminant value read",
8182
EvalError::PointerOutOfBounds { .. } =>
8283
"pointer offset outside bounds of allocation",
84+
EvalError::NullPointerOutOfBounds =>
85+
"invalid NULL pointer offset",
8386
EvalError::ReadPointerAsBytes =>
8487
"a raw memory access tried to access part of a pointer value as raw bytes",
8588
EvalError::ReadBytesAsPointer =>
8689
"a memory access tried to interpret some bytes as a pointer",
8790
EvalError::InvalidPointerMath =>
88-
"attempted to do math or a comparison on pointers into different allocations",
91+
"attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. compating pointers into different allocations",
8992
EvalError::ReadUndefBytes =>
9093
"attempted to read undefined bytes",
9194
EvalError::DeadLocal =>

src/eval_context.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -892,19 +892,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
892892
}
893893

894894
pub(super) fn pointer_offset(&self, ptr: PrimVal, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, PrimVal> {
895-
if offset == 0 {
896-
// rustc relies on Offset-by-0 to be well-defined even for "bad" pointers like Unique::empty().
897-
return Ok(ptr);
895+
// This function raises an error if the offset moves the pointer outside of its allocation. We consider
896+
// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
897+
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
898+
// allocation.
899+
900+
if ptr.is_null()? { // NULL pointers must only be offset by 0
901+
return if offset == 0 { Ok(ptr) } else { Err(EvalError::NullPointerOutOfBounds) };
898902
}
899903
// FIXME: assuming here that type size is < i64::max_value()
900904
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
901-
if pointee_size == 0 {
902-
// rustc relies on offsetting pointers to zsts to be a nop
903-
return Ok(ptr);
904-
}
905905
return if let Some(offset) = offset.checked_mul(pointee_size) {
906906
let ptr = ptr.signed_offset(offset, self.memory.layout)?;
907-
self.memory.check_bounds(ptr.to_ptr()?, false)?;
907+
// Do not do bounds-checking for integers or ZST; they can never alias a normal pointer anyway.
908+
if let PrimVal::Ptr(ptr) = ptr {
909+
if !(ptr.points_to_zst() && (offset == 0 || pointee_size == 0)) {
910+
self.memory.check_bounds(ptr, false)?;
911+
}
912+
} else if ptr.is_null()? {
913+
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
914+
return Err(EvalError::NullPointerOutOfBounds);
915+
}
908916
Ok(ptr)
909917
} else {
910918
Err(EvalError::OverflowingMath)

src/terminator/mod.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
585585
}
586586

587587
"dlsym" => {
588-
let handle = args[0].read_ptr(&self.memory)?;
589-
{
590-
let symbol = args[1].read_ptr(&self.memory)?.to_ptr()?;
591-
let symbol_name = self.memory.read_c_str(symbol)?;
592-
let err = format!("bad c unicode symbol: {:?}", symbol_name);
593-
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
594-
return Err(EvalError::Unimplemented(format!("miri does not support dynamically loading libraries (requested symbol: {})", symbol_name)));
595-
}
588+
let _handle = args[0].read_ptr(&self.memory)?;
589+
let symbol = args[1].read_ptr(&self.memory)?.to_ptr()?;
590+
let symbol_name = self.memory.read_c_str(symbol)?;
591+
let err = format!("bad c unicode symbol: {:?}", symbol_name);
592+
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
593+
return Err(EvalError::Unimplemented(format!("miri does not support dynamically loading libraries (requested symbol: {})", symbol_name)));
596594
}
597595

598596
"__rust_allocate" => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
fn main() {
22
let x: *const u8 = &1;
33
let y: *const u8 = &2;
4-
if x < y { //~ ERROR: attempted to do math or a comparison on pointers into different allocations
4+
if x < y { //~ ERROR: attempted to do invalid arithmetic on pointers
55
unreachable!()
66
}
77
}

0 commit comments

Comments
 (0)