Skip to content

Commit de78cb5

Browse files
committed
on a signed deref check, mention the right pointer in the error
1 parent 70591dc commit de78cb5

34 files changed

+192
-141
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 25 additions & 10 deletions
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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
295295
);
296296
}
297297

298-
match self.ptr_try_get_alloc_id(ptr) {
298+
match self.ptr_try_get_alloc_id(ptr, 0) {
299299
Ok((alloc_id, offset, _extra)) => {
300300
let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id);
301301

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

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

compiler/rustc_const_eval/src/errors.rs

Lines changed: 18 additions & 13 deletions
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::codes::*;
@@ -15,7 +16,7 @@ use rustc_middle::mir::interpret::{
1516
use rustc_middle::ty::{self, Mutability, Ty};
1617
use rustc_span::Span;
1718
use rustc_target::abi::call::AdjustForForeignAbiError;
18-
use rustc_target::abi::{Size, WrappingRange};
19+
use rustc_target::abi::WrappingRange;
1920

2021
use crate::interpret::InternKind;
2122

@@ -575,18 +576,21 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
575576
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
576577
}
577578
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
578-
diag.arg("alloc_size", alloc_size.bytes())
579-
.arg("inbounds_size", inbounds_size.bytes())
580-
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
581-
diag.arg(
582-
"pointer",
583-
Pointer::new(
584-
Some(CtfeProvenance::from(alloc_id)),
585-
Size::from_bytes(ptr_offset as u64),
586-
)
587-
.to_string(),
588-
);
579+
diag.arg("alloc_size", alloc_size.bytes());
580+
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
581+
diag.arg("pointer", {
582+
let mut out = format!("{:?}", alloc_id);
583+
if ptr_offset > 0 {
584+
write!(out, "+{:#x}", ptr_offset).unwrap();
585+
} else if ptr_offset < 0 {
586+
write!(out, "-{:#x}", ptr_offset.unsigned_abs()).unwrap();
587+
}
588+
out
589+
});
590+
diag.arg("inbounds_size_is_neg", inbounds_size < 0);
591+
diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
589592
diag.arg("ptr_offset_is_neg", ptr_offset < 0);
593+
diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
590594
diag.arg(
591595
"alloc_size_minus_ptr_offset",
592596
alloc_size.bytes().saturating_sub(ptr_offset as u64),
@@ -600,7 +604,8 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
600604
);
601605
}
602606

603-
diag.arg("inbounds_size", inbounds_size.bytes());
607+
diag.arg("inbounds_size_is_neg", inbounds_size < 0);
608+
diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
604609
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
605610
}
606611
AlignmentCheckFailed(Misalignment { required, has }, msg) => {

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
243243
let (a_offset, b_offset, is_addr) = if M::Provenance::OFFSET_IS_ADDR {
244244
(a.addr().bytes(), b.addr().bytes(), /*is_addr*/ true)
245245
} else {
246-
match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
246+
match (self.ptr_try_get_alloc_id(a, 0), self.ptr_try_get_alloc_id(b, 0)) {
247247
(Err(a), Err(b)) => {
248248
// Neither pointer points to an allocation, so they are both absolute.
249249
(a, b, /*is_addr*/ true)
@@ -312,7 +312,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
312312
};
313313

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

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,21 @@ pub trait Machine<'tcx>: Sized {
321321
ptr: Pointer<Self::Provenance>,
322322
) -> InterpResult<'tcx>;
323323

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

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

0 commit comments

Comments
 (0)