Skip to content

Commit 56c698c

Browse files
committed
Auto merge of rust-lang#128334 - matthiaskrgr:rollup-nhxdt0c, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#128182 (handle no_std targets on std builds) - rust-lang#128277 (miri: fix offset_from behavior on wildcard pointers) - rust-lang#128304 (Isolate the diagnostic code that expects `thir::Pat` to be printable) - rust-lang#128307 (Clean and enable `rustdoc::unescaped_backticks` for `core/alloc/std/test/proc_macro`) - rust-lang#128322 (CI: move RFL job forward to v6.11-rc1) - rust-lang#128333 (Miri subtree update) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 80d8270 + 624f9bd commit 56c698c

File tree

145 files changed

+1240
-552
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+1240
-552
lines changed

compiler/rustc_const_eval/messages.ftl

+23-11
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ const_eval_copy_nonoverlapping_overlapping =
4545
`copy_nonoverlapping` called on overlapping ranges
4646
4747
const_eval_dangling_int_pointer =
48-
{$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance)
48+
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} which is a dangling pointer (it has no provenance)
4949
const_eval_dangling_null_pointer =
50-
{$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance)
50+
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got a null pointer
5151
5252
const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind}
5353
const_eval_dead_local =
@@ -87,6 +87,13 @@ const_eval_error = {$error_kind ->
8787
const_eval_exact_div_has_remainder =
8888
exact_div: {$a} cannot be divided by {$b} without remainder
8989
90+
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
95+
}
96+
9097
const_eval_extern_static =
9198
cannot access extern static ({$did})
9299
const_eval_extern_type_field = `extern type` field does not have a known offset
@@ -233,16 +240,17 @@ const_eval_nullary_intrinsic_fail =
233240
234241
const_eval_offset_from_different_allocations =
235242
`{$name}` called on pointers into different allocations
236-
const_eval_offset_from_different_integers =
237-
`{$name}` called on different pointers without provenance (i.e., without an associated allocation)
238243
const_eval_offset_from_overflow =
239244
`{$name}` called when first pointer is too far ahead of second
240245
const_eval_offset_from_test =
241246
out-of-bounds `offset_from`
242247
const_eval_offset_from_underflow =
243248
`{$name}` called when first pointer is too far before second
244249
const_eval_offset_from_unsigned_overflow =
245-
`ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
250+
`ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr ->
251+
[true] address
252+
*[false] offset
253+
} than second: {$a_offset} < {$b_offset}
246254
247255
const_eval_operator_non_const =
248256
cannot call non-const operator in {const_eval_const_context}s
@@ -264,10 +272,16 @@ const_eval_pointer_arithmetic_overflow =
264272
overflowing in-bounds pointer arithmetic
265273
const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic
266274
const_eval_pointer_out_of_bounds =
267-
{$bad_pointer_message}: {$alloc_id} has size {$alloc_size}, so pointer to {$ptr_size} {$ptr_size ->
268-
[1] byte
269-
*[many] bytes
270-
} starting at offset {$ptr_offset} is out-of-bounds
275+
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg ->
276+
[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
281+
}
282+
*[x] and there are only {$alloc_size_minus_ptr_offset} bytes starting at that pointer
283+
}
284+
}
271285
const_eval_pointer_use_after_free =
272286
{$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
273287
const_eval_ptr_as_bytes_1 =
@@ -465,5 +479,3 @@ const_eval_write_through_immutable_pointer =
465479
466480
const_eval_write_to_read_only =
467481
writing to {$allocation} which is read-only
468-
const_eval_zst_pointer_out_of_bounds =
469-
{$bad_pointer_message}: {$alloc_id} has size {$alloc_size}, so pointer at offset {$ptr_offset} is out-of-bounds

compiler/rustc_const_eval/src/errors.rs

+28-14
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use rustc_errors::{
88
use rustc_hir::ConstContext;
99
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
1010
use rustc_middle::mir::interpret::{
11-
CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, Misalignment,
12-
PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
13-
ValidationErrorInfo,
11+
CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpError, InvalidMetaKind,
12+
InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo,
13+
UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
1414
};
1515
use rustc_middle::ty::{self, Mutability, Ty};
1616
use rustc_span::Span;
@@ -490,10 +490,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
490490
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
491491
UnterminatedCString(_) => const_eval_unterminated_c_string,
492492
PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
493-
PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
494493
PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
495-
DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
496-
DanglingIntPointer(_, _) => const_eval_dangling_int_pointer,
494+
DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer,
495+
DanglingIntPointer { .. } => const_eval_dangling_int_pointer,
497496
AlignmentCheckFailed { .. } => const_eval_alignment_check_failed,
498497
WriteToReadOnly(_) => const_eval_write_to_read_only,
499498
DerefFunctionPointer(_) => const_eval_deref_function_pointer,
@@ -575,18 +574,33 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
575574
diag.arg("alloc_id", alloc_id)
576575
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
577576
}
578-
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
579-
diag.arg("alloc_id", alloc_id)
580-
.arg("alloc_size", alloc_size.bytes())
581-
.arg("ptr_offset", ptr_offset)
582-
.arg("ptr_size", ptr_size.bytes())
577+
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())
583580
.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+
);
589+
diag.arg("ptr_offset_is_neg", ptr_offset < 0);
590+
diag.arg(
591+
"alloc_size_minus_ptr_offset",
592+
alloc_size.bytes().saturating_sub(ptr_offset as u64),
593+
);
584594
}
585-
DanglingIntPointer(ptr, msg) => {
586-
if ptr != 0 {
587-
diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
595+
DanglingIntPointer { addr, inbounds_size, msg } => {
596+
if addr != 0 {
597+
diag.arg(
598+
"pointer",
599+
Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(),
600+
);
588601
}
589602

603+
diag.arg("inbounds_size", inbounds_size.bytes());
590604
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
591605
}
592606
AlignmentCheckFailed(Misalignment { required, has }, msg) => {

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+36-47
Original file line numberDiff line numberDiff line change
@@ -238,36 +238,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
238238
let isize_layout = self.layout_of(self.tcx.types.isize)?;
239239

240240
// Get offsets for both that are at least relative to the same base.
241-
let (a_offset, b_offset) =
241+
// With `OFFSET_IS_ADDR` this is trivial; without it we need either
242+
// two integers or two pointers into the same allocation.
243+
let (a_offset, b_offset, is_addr) = if M::Provenance::OFFSET_IS_ADDR {
244+
(a.addr().bytes(), b.addr().bytes(), /*is_addr*/ true)
245+
} else {
242246
match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
243247
(Err(a), Err(b)) => {
244-
// Neither pointer points to an allocation.
245-
// This is okay only if they are the same.
246-
if a != b {
247-
// We'd catch this below in the "dereferenceable" check, but
248-
// show a nicer error for this particular case.
249-
throw_ub_custom!(
250-
fluent::const_eval_offset_from_different_integers,
251-
name = intrinsic_name,
252-
);
253-
}
254-
// This will always return 0.
255-
(a, b)
256-
}
257-
_ if M::Provenance::OFFSET_IS_ADDR && a.addr() == b.addr() => {
258-
// At least one of the pointers has provenance, but they also point to
259-
// the same address so it doesn't matter; this is fine. `(0, 0)` means
260-
// we pass all the checks below and return 0.
261-
(0, 0)
248+
// Neither pointer points to an allocation, so they are both absolute.
249+
(a, b, /*is_addr*/ true)
262250
}
263-
// From here onwards, the pointers are definitely for different addresses
264-
// (or we can't determine their absolute address).
265251
(Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _)))
266252
if a_alloc_id == b_alloc_id =>
267253
{
268254
// Found allocation for both, and it's the same.
269255
// Use these offsets for distance calculation.
270-
(a_offset.bytes(), b_offset.bytes())
256+
(a_offset.bytes(), b_offset.bytes(), /*is_addr*/ false)
271257
}
272258
_ => {
273259
// Not into the same allocation -- this is UB.
@@ -276,9 +262,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
276262
name = intrinsic_name,
277263
);
278264
}
279-
};
265+
}
266+
};
280267

281-
// Compute distance.
268+
// Compute distance: a - b.
282269
let dist = {
283270
// Addresses are unsigned, so this is a `usize` computation. We have to do the
284271
// overflow check separately anyway.
@@ -295,6 +282,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
295282
fluent::const_eval_offset_from_unsigned_overflow,
296283
a_offset = a_offset,
297284
b_offset = b_offset,
285+
is_addr = is_addr,
298286
);
299287
}
300288
// The signed form of the intrinsic allows this. If we interpret the
@@ -323,14 +311,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
323311
}
324312
};
325313

326-
// Check that the range between them is dereferenceable ("in-bounds or one past the
327-
// end of the same allocation"). This is like the check in ptr_offset_inbounds.
328-
let min_ptr = if dist >= 0 { b } else { a };
329-
self.check_ptr_access(
330-
min_ptr,
331-
Size::from_bytes(dist.unsigned_abs()),
314+
// 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`.
316+
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?;
317+
// Then check that this is also dereferenceable from `a`. This ensures that they are
318+
// derived from the same allocation.
319+
self.check_ptr_access_signed(
320+
a,
321+
dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large
332322
CheckInAllocMsg::OffsetFromTest,
333-
)?;
323+
)
324+
.map_err(|_| {
325+
// Make the error more specific.
326+
err_ub_custom!(
327+
fluent::const_eval_offset_from_different_allocations,
328+
name = intrinsic_name,
329+
)
330+
})?;
334331

335332
// Perform division by size to compute return value.
336333
let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
@@ -577,27 +574,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
577574
}
578575

579576
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
580-
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
581-
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
577+
/// allocation.
582578
pub fn ptr_offset_inbounds(
583579
&self,
584580
ptr: Pointer<Option<M::Provenance>>,
585581
offset_bytes: i64,
586582
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
587-
// The offset being in bounds cannot rely on "wrapping around" the address space.
588-
// So, first rule out overflows in the pointer arithmetic.
589-
let offset_ptr = ptr.signed_offset(offset_bytes, self)?;
590-
// ptr and offset_ptr must be in bounds of the same allocated object. This means all of the
591-
// memory between these pointers must be accessible. Note that we do not require the
592-
// pointers to be properly aligned (unlike a read/write operation).
593-
let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
594-
// This call handles checking for integer/null pointers.
595-
self.check_ptr_access(
596-
min_ptr,
597-
Size::from_bytes(offset_bytes.unsigned_abs()),
598-
CheckInAllocMsg::PointerArithmeticTest,
599-
)?;
600-
Ok(offset_ptr)
583+
// We first compute the pointer with overflow checks, to get a specific error for when it
584+
// overflows (though technically this is redundant with the following inbounds check).
585+
let result = ptr.signed_offset(offset_bytes, self)?;
586+
// The offset must be in bounds starting from `ptr`.
587+
self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?;
588+
// Done.
589+
Ok(result)
601590
}
602591

603592
/// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.

compiler/rustc_const_eval/src/interpret/memory.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
411411
Ok(())
412412
}
413413

414+
/// Check whether the given pointer points to live memory for a signed amount of bytes.
415+
/// A negative amounts means that the given range of memory to the left of the pointer
416+
/// needs to be dereferenceable.
417+
pub fn check_ptr_access_signed(
418+
&self,
419+
ptr: Pointer<Option<M::Provenance>>,
420+
size: i64,
421+
msg: CheckInAllocMsg,
422+
) -> InterpResult<'tcx> {
423+
if let Ok(size) = u64::try_from(size) {
424+
self.check_ptr_access(ptr, Size::from_bytes(size), msg)
425+
} else {
426+
// Compute the pointer at the beginning of the range, and do the standard
427+
// dereferenceability check from there.
428+
let begin_ptr = ptr.wrapping_signed_offset(size, self);
429+
self.check_ptr_access(begin_ptr, Size::from_bytes(size.unsigned_abs()), msg)
430+
}
431+
}
432+
414433
/// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
415434
/// to the allocation it points to. Supports both shared and mutable references, as the actual
416435
/// checking is offloaded to a helper closure.
@@ -437,7 +456,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
437456
Ok(match self.ptr_try_get_alloc_id(ptr) {
438457
Err(addr) => {
439458
// We couldn't get a proper allocation.
440-
throw_ub!(DanglingIntPointer(addr, msg));
459+
throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg });
441460
}
442461
Ok((alloc_id, offset, prov)) => {
443462
let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
@@ -448,7 +467,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
448467
alloc_id,
449468
alloc_size,
450469
ptr_offset: self.target_usize_to_isize(offset.bytes()),
451-
ptr_size: size,
470+
inbounds_size: size,
452471
msg,
453472
})
454473
}
@@ -1421,7 +1440,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14211440
ptr: Pointer<Option<M::Provenance>>,
14221441
) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> {
14231442
self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
1424-
err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
1443+
err_ub!(DanglingIntPointer {
1444+
addr: offset,
1445+
// We don't know the actually required size.
1446+
inbounds_size: Size::ZERO,
1447+
msg: CheckInAllocMsg::InboundsTest
1448+
})
1449+
.into()
14251450
})
14261451
}
14271452
}

compiler/rustc_const_eval/src/interpret/validity.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
348348
try_validation!(
349349
self.ecx.get_ptr_vtable_ty(vtable, Some(data)),
350350
self.path,
351-
Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) =>
351+
Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) =>
352352
InvalidVTablePtr { value: format!("{vtable}") },
353353
Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => {
354354
InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait }
@@ -405,8 +405,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
405405
CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
406406
),
407407
self.path,
408-
Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind },
409-
Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance {
408+
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },
409+
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
410410
ptr_kind,
411411
// FIXME this says "null pointer" when null but we need translate
412412
pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(*i))
@@ -605,7 +605,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
605605
let _fn = try_validation!(
606606
self.ecx.get_ptr_fn(ptr),
607607
self.path,
608-
Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) =>
608+
Ub(DanglingIntPointer{ .. } | InvalidFunctionPointer(..)) =>
609609
InvalidFnPtr { value: format!("{ptr}") },
610610
);
611611
// FIXME: Check if the signature matches

0 commit comments

Comments
 (0)