diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-03-11 20:29:45 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-11 20:29:45 +0100 |
| commit | 9e70b1a033ec27d618b8e9ffa9412837b7545276 (patch) | |
| tree | 7a0c67489ce634e50e75f272b9c3c9c4d6fc5b3a /compiler/rustc_const_eval/src | |
| parent | fedf70acb1e8a51c36a970bf20aa4e6febf815f9 (diff) | |
| parent | 63ed8e41ce1f126827055b3b6b35db734d3cca28 (diff) | |
| download | rust-9e70b1a033ec27d618b8e9ffa9412837b7545276.tar.gz rust-9e70b1a033ec27d618b8e9ffa9412837b7545276.zip | |
Rollup merge of #94827 - RalfJung:offset-from-ub, r=oli-obk
CTFE/Miri: detect out-of-bounds pointers in offset_from Also I became uneasy with aggressively doing `try_to_int` here -- this will always succeed on Miri, leading to the wrong codepath being taken. We should rather try to convert them both to pointers, and use the integer path as a fallback, so that's what I implemented now. Hiding whitespaces helps with the diff. Fixes https://github.com/rust-lang/miri/issues/1950 r? ``@oli-obk``
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/intrinsics.rs | 80 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/memory.rs | 6 |
2 files changed, 45 insertions, 41 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 715b174491b..a39ef22ec08 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -307,53 +307,57 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_pointer(offset_ptr, dest)?; } sym::ptr_offset_from => { - let a = self.read_immediate(&args[0])?.to_scalar()?; - let b = self.read_immediate(&args[1])?.to_scalar()?; + let a = self.read_pointer(&args[0])?; + let b = self.read_pointer(&args[1])?; // Special case: if both scalars are *equal integers* // and not null, we pretend there is an allocation of size 0 right there, // and their offset is 0. (There's never a valid object at null, making it an // exception from the exception.) // This is the dual to the special exception for offset-by-0 - // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`). - // - // Control flow is weird because we cannot early-return (to reach the - // `go_to_block` at the end). - let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) { - let a = a.try_to_machine_usize(*self.tcx).unwrap(); - let b = b.try_to_machine_usize(*self.tcx).unwrap(); - if a == b && a != 0 { + // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below). + match (self.memory.ptr_try_get_alloc(a), self.memory.ptr_try_get_alloc(b)) { + (Err(a), Err(b)) if a == b && a != 0 => { + // Both are the same non-null integer. self.write_scalar(Scalar::from_machine_isize(0, self), dest)?; - true - } else { - false } - } else { - false - }; - - if !done { - // General case: we need two pointers. - let a = self.scalar_to_ptr(a); - let b = self.scalar_to_ptr(b); - let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?; - let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?; - if a_alloc_id != b_alloc_id { - throw_ub_format!( - "ptr_offset_from cannot compute offset of pointers into different \ - allocations.", - ); + (Err(offset), _) | (_, Err(offset)) => { + throw_ub!(DanglingIntPointer(offset, CheckInAllocMsg::OffsetFromTest)); + } + (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => { + // Both are pointers. They must be into the same allocation. + if a_alloc_id != b_alloc_id { + throw_ub_format!( + "ptr_offset_from cannot compute offset of pointers into different \ + allocations.", + ); + } + // And they must both be valid for zero-sized accesses ("in-bounds or one past the end"). + self.memory.check_ptr_access_align( + a, + Size::ZERO, + Align::ONE, + CheckInAllocMsg::OffsetFromTest, + )?; + self.memory.check_ptr_access_align( + b, + Size::ZERO, + Align::ONE, + CheckInAllocMsg::OffsetFromTest, + )?; + + // Compute offset. + let usize_layout = self.layout_of(self.tcx.types.usize)?; + let isize_layout = self.layout_of(self.tcx.types.isize)?; + let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout); + let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout); + let (val, _overflowed, _ty) = + self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; + let pointee_layout = self.layout_of(substs.type_at(0))?; + let val = ImmTy::from_scalar(val, isize_layout); + let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); + self.exact_div(&val, &size, dest)?; } - let usize_layout = self.layout_of(self.tcx.types.usize)?; - let isize_layout = self.layout_of(self.tcx.types.isize)?; - let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout); - let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout); - let (val, _overflowed, _ty) = - self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; - let pointee_layout = self.layout_of(substs.type_at(0))?; - let val = ImmTy::from_scalar(val, isize_layout); - let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); - self.exact_div(&val, &size, dest)?; } } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 5fe4672f17e..6397fcaaf8d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -388,9 +388,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => { AllocCheck::Dereferenceable } - CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => { - AllocCheck::Live - } + CheckInAllocMsg::PointerArithmeticTest + | CheckInAllocMsg::OffsetFromTest + | CheckInAllocMsg::InboundsTest => AllocCheck::Live, }; let (size, align) = self.get_size_and_align(alloc_id, check)?; Ok((size, align, ())) |
