Skip to content

Commit 5802bda

Browse files
committed
on a signed deref check, mention the right pointer in the error
1 parent f8ebe8d commit 5802bda

30 files changed

+184
-128
lines changed

compiler/rustc_const_eval/messages.ftl

+25-10
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,18 @@ const_eval_exact_div_has_remainder =
8888
exact_div: {$a} cannot be divided by {$b} without remainder
8989
9090
const_eval_expected_inbounds_pointer =
91-
expected {$inbounds_size ->
92-
[0] a pointer to some allocation
93-
[1] a pointer to 1 byte of memory
94-
*[x] a pointer to {$inbounds_size} bytes of memory
91+
expected a pointer to {$inbounds_size_abs ->
92+
[0] some allocation
93+
*[x] {$inbounds_size_is_neg ->
94+
[false] {$inbounds_size_abs ->
95+
[1] 1 byte of memory
96+
*[x] {$inbounds_size_abs} bytes of memory
97+
}
98+
*[true] the end of {$inbounds_size_abs ->
99+
[1] 1 byte of memory
100+
*[x] {$inbounds_size_abs} bytes of memory
101+
}
102+
}
95103
}
96104
97105
const_eval_extern_static =
@@ -243,7 +251,7 @@ const_eval_offset_from_different_allocations =
243251
const_eval_offset_from_overflow =
244252
`{$name}` called when first pointer is too far ahead of second
245253
const_eval_offset_from_test =
246-
out-of-bounds `offset_from`
254+
out-of-bounds `offset_from` origin
247255
const_eval_offset_from_underflow =
248256
`{$name}` called when first pointer is too far before second
249257
const_eval_offset_from_unsigned_overflow =
@@ -274,12 +282,19 @@ const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic
274282
const_eval_pointer_out_of_bounds =
275283
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg ->
276284
[true] which points to before the beginning of the allocation
277-
*[false] {$alloc_size_minus_ptr_offset ->
278-
[0] which is at or beyond the end of the allocation of size {$alloc_size ->
279-
[1] 1 byte
280-
*[x] {$alloc_size} bytes
285+
*[false] {$inbounds_size_is_neg ->
286+
[true] {$ptr_offset_abs ->
287+
[0] which is at the beginning of the allocation
288+
*[other] which does not have enough space to the beginning of the allocation
289+
}
290+
*[false] {$alloc_size_minus_ptr_offset ->
291+
[0] which is at or beyond the end of the allocation of size {$alloc_size ->
292+
[1] 1 byte
293+
*[x] {$alloc_size} bytes
294+
}
295+
[1] which is only 1 byte from the end of the allocation
296+
*[x] which is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
281297
}
282-
*[x] and there are only {$alloc_size_minus_ptr_offset} bytes starting at that pointer
283298
}
284299
}
285300
const_eval_pointer_use_after_free =

compiler/rustc_const_eval/src/const_eval/machine.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
299299
);
300300
}
301301

302-
match self.ptr_try_get_alloc_id(ptr) {
302+
match self.ptr_try_get_alloc_id(ptr, 0) {
303303
Ok((alloc_id, offset, _extra)) => {
304304
let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id);
305305

@@ -514,7 +514,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
514514

515515
// If an allocation is created in an another const,
516516
// we don't deallocate it.
517-
let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr)?;
517+
let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr, 0)?;
518518
let is_allocated_in_another_const = matches!(
519519
ecx.tcx.try_get_global_alloc(alloc_id),
520520
Some(interpret::GlobalAlloc::Memory(_))

compiler/rustc_const_eval/src/errors.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::borrow::Cow;
2+
use std::fmt::Write;
23

34
use either::Either;
45
use rustc_errors::{
@@ -14,7 +15,7 @@ use rustc_middle::mir::interpret::{
1415
use rustc_middle::ty::{self, Mutability, Ty};
1516
use rustc_span::Span;
1617
use rustc_target::abi::call::AdjustForForeignAbiError;
17-
use rustc_target::abi::{Size, WrappingRange};
18+
use rustc_target::abi::WrappingRange;
1819

1920
use crate::interpret::InternKind;
2021

@@ -573,18 +574,21 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
573574
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
574575
}
575576
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
576-
diag.arg("alloc_size", alloc_size.bytes())
577-
.arg("inbounds_size", inbounds_size.bytes())
578-
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
579-
diag.arg(
580-
"pointer",
581-
Pointer::new(
582-
Some(CtfeProvenance::from(alloc_id)),
583-
Size::from_bytes(ptr_offset as u64),
584-
)
585-
.to_string(),
586-
);
577+
diag.arg("alloc_size", alloc_size.bytes());
578+
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
579+
diag.arg("pointer", {
580+
let mut out = format!("{:?}", alloc_id);
581+
if ptr_offset > 0 {
582+
write!(out, "+{:#x}", ptr_offset).unwrap();
583+
} else if ptr_offset < 0 {
584+
write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap();
585+
}
586+
out
587+
});
588+
diag.arg("inbounds_size_is_neg", inbounds_size < 0);
589+
diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
587590
diag.arg("ptr_offset_is_neg", ptr_offset < 0);
591+
diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
588592
diag.arg(
589593
"alloc_size_minus_ptr_offset",
590594
alloc_size.bytes().saturating_sub(ptr_offset as u64),
@@ -598,7 +602,8 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
598602
);
599603
}
600604

601-
diag.arg("inbounds_size", inbounds_size.bytes());
605+
diag.arg("inbounds_size_is_neg", inbounds_size < 0);
606+
diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
602607
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
603608
}
604609
AlignmentCheckFailed(Misalignment { required, has }, msg) => {

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
248248
let (a_offset, b_offset, is_addr) = if M::Provenance::OFFSET_IS_ADDR {
249249
(a.addr().bytes(), b.addr().bytes(), /*is_addr*/ true)
250250
} else {
251-
match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
251+
match (self.ptr_try_get_alloc_id(a, 0), self.ptr_try_get_alloc_id(b, 0)) {
252252
(Err(a), Err(b)) => {
253253
// Neither pointer points to an allocation, so they are both absolute.
254254
(a, b, /*is_addr*/ true)
@@ -317,7 +317,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
317317
};
318318

319319
// Check that the memory between them is dereferenceable at all, starting from the
320-
// base pointer: `dist` is `a - b`, so it is based on `b`.
320+
// origin pointer: `dist` is `a - b`, so it is based on `b`.
321321
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?;
322322
// Then check that this is also dereferenceable from `a`. This ensures that they are
323323
// derived from the same allocation.

compiler/rustc_const_eval/src/interpret/machine.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -322,15 +322,21 @@ pub trait Machine<'tcx>: Sized {
322322
ptr: Pointer<Self::Provenance>,
323323
) -> InterpResult<'tcx>;
324324

325-
/// Convert a pointer with provenance into an allocation-offset pair
326-
/// and extra provenance info.
325+
/// Convert a pointer with provenance into an allocation-offset pair and extra provenance info.
326+
/// `size` says how many bytes of memory are expected at that pointer. The *sign* of `size` can
327+
/// be used to disambiguate situations where a wildcard pointer sits right in between two
328+
/// allocations.
327329
///
328-
/// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
330+
/// If `ptr.provenance.get_alloc_id()` is `Some(p)`, the returned `AllocId` must be `p`.
331+
/// The resulting `AllocId` will just be used for that one step and the forgotten again
332+
/// (i.e., we'll never turn the data returned here back into a `Pointer` that might be
333+
/// stored in machine state).
329334
///
330335
/// When this fails, that means the pointer does not point to a live allocation.
331336
fn ptr_get_alloc(
332337
ecx: &InterpCx<'tcx, Self>,
333338
ptr: Pointer<Self::Provenance>,
339+
size: i64,
334340
) -> Option<(AllocId, Size, Self::ProvenanceExtra)>;
335341

336342
/// Called to adjust global allocations to the Provenance and AllocExtra of this machine.
@@ -659,6 +665,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
659665
fn ptr_get_alloc(
660666
_ecx: &InterpCx<$tcx, Self>,
661667
ptr: Pointer<CtfeProvenance>,
668+
_size: i64,
662669
) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
663670
// We know `offset` is relative to the allocation, so we can use `into_parts`.
664671
let (prov, offset) = ptr.into_parts();

0 commit comments

Comments
 (0)