Skip to content

Commit 575f024

Browse files
committed
add const_leak and reject interning non-leaked const_allocate ptrs
1 parent 8df4a58 commit 575f024

23 files changed

+206
-18
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ const_eval_const_context = {$kind ->
5656
*[other] {""}
5757
}
5858
59+
const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global
60+
.note = use `const_make_global` to make allocated pointers immutable before returning
61+
62+
const_eval_const_make_global_invalid_pointer = invalid pointer passed to `const_make_global`
63+
5964
const_eval_copy_nonoverlapping_overlapping =
6065
`copy_nonoverlapping` called on overlapping ranges
6166
@@ -338,6 +343,7 @@ const_eval_realloc_or_alloc_with_offset =
338343
{$kind ->
339344
[dealloc] deallocating
340345
[realloc] reallocating
346+
[leak] leaking
341347
*[other] {""}
342348
} {$ptr} which does not point to the beginning of an object
343349

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
9393
// Since evaluation had no errors, validate the resulting constant.
9494
const_validate_mplace(ecx, &ret, cid)?;
9595

96-
// Only report this after validation, as validaiton produces much better diagnostics.
96+
// Only report this after validation, as validation produces much better diagnostics.
9797
// FIXME: ensure validation always reports this and stop making interning care about it.
9898

9999
match intern_result {

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ impl interpret::MayLeak for MemoryKind {
189189
}
190190
}
191191

192+
impl interpret::IsConstHeap for MemoryKind {
193+
#[inline(always)]
194+
fn is_const_heap(&self) -> bool {
195+
match self {
196+
MemoryKind::Heap => true,
197+
}
198+
}
199+
}
200+
192201
impl interpret::MayLeak for ! {
193202
#[inline(always)]
194203
fn may_leak(self) -> bool {
@@ -197,6 +206,13 @@ impl interpret::MayLeak for ! {
197206
}
198207
}
199208

209+
impl interpret::IsConstHeap for ! {
210+
#[inline(always)]
211+
fn is_const_heap(&self) -> bool {
212+
*self
213+
}
214+
}
215+
200216
impl<'tcx> CompileTimeInterpCx<'tcx> {
201217
fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
202218
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
@@ -457,6 +473,37 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
457473
)?;
458474
}
459475
}
476+
477+
sym::const_make_global => {
478+
let ptr = ecx.read_pointer(&args[0])?;
479+
let size = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?;
480+
let align = ecx.read_scalar(&args[2])?.to_target_usize(ecx)?;
481+
482+
let _size: Size = Size::from_bytes(size);
483+
let _align = match Align::from_bytes(align) {
484+
Ok(a) => a,
485+
Err(err) => throw_ub_custom!(
486+
fluent::const_eval_invalid_align_details,
487+
name = "const_make_global",
488+
err_kind = err.diag_ident(),
489+
align = err.align()
490+
),
491+
};
492+
493+
let (alloc_id, _, _) = ecx.ptr_get_alloc_id(ptr, 0)?;
494+
let is_allocated_in_another_const = matches!(
495+
ecx.tcx.try_get_global_alloc(alloc_id),
496+
Some(interpret::GlobalAlloc::Memory(_))
497+
);
498+
499+
if !is_allocated_in_another_const {
500+
ecx.leak_const_heap_ptr(ptr)?;
501+
ecx.write_pointer(ptr, dest)?;
502+
} else {
503+
throw_ub_custom!(fluent::const_eval_const_make_global_invalid_pointer);
504+
}
505+
}
506+
460507
// The intrinsic represents whether the value is known to the optimizer (LLVM).
461508
// We're not doing any optimizations here, so there is no optimizer that could know the value.
462509
// (We know the value here in the machine of course, but this is the runtime of that code,

compiler/rustc_const_eval/src/errors.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ pub(crate) struct MutablePtrInFinal {
4343
pub kind: InternKind,
4444
}
4545

46+
#[derive(Diagnostic)]
47+
#[diag(const_eval_const_heap_ptr_in_final)]
48+
#[note]
49+
pub(crate) struct ConstHeapPtrInFinal {
50+
#[primary_span]
51+
pub span: Span,
52+
}
53+
4654
#[derive(Diagnostic)]
4755
#[diag(const_eval_unstable_in_stable_exposed)]
4856
pub(crate) struct UnstableInStableExposed {

compiler/rustc_const_eval/src/interpret/intern.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ use rustc_span::def_id::LocalDefId;
2727
use tracing::{instrument, trace};
2828

2929
use super::{
30-
AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok,
30+
AllocId, Allocation, InterpCx, IsConstHeap, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub,
31+
interp_ok,
3132
};
3233
use crate::const_eval;
3334
use crate::const_eval::DummyMachine;
34-
use crate::errors::NestedStaticInThreadLocal;
35+
use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal};
3536

3637
pub trait CompileTimeMachine<'tcx, T> = Machine<
3738
'tcx,
@@ -62,7 +63,7 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
6263
/// already mutable (as a sanity check).
6364
///
6465
/// Returns an iterator over all relocations referred to by this allocation.
65-
fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
66+
fn intern_shallow<'tcx, T: IsConstHeap, M: CompileTimeMachine<'tcx, T>>(
6667
ecx: &mut InterpCx<'tcx, M>,
6768
alloc_id: AllocId,
6869
mutability: Mutability,
@@ -71,9 +72,20 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
7172
trace!("intern_shallow {:?}", alloc_id);
7273
// remove allocation
7374
// FIXME(#120456) - is `swap_remove` correct?
74-
let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
75+
let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
7576
return Err(());
7677
};
78+
79+
match kind {
80+
MemoryKind::Machine(x) if x.is_const_heap() => {
81+
// attempting to intern a `const_allocate`d pointer that was not made global via
82+
// `const_make_global`. We emit an error here but don't return an `Err` as if we
83+
// did the caller assumes we found a dangling pointer.
84+
ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span });
85+
}
86+
MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {}
87+
}
88+
7789
// Set allocation mutability as appropriate. This is used by LLVM to put things into
7890
// read-only memory, and also by Miri when evaluating other globals that
7991
// access this one.
@@ -99,7 +111,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
99111
} else {
100112
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
101113
}
102-
Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
114+
Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov))
103115
}
104116

105117
/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
@@ -321,7 +333,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
321333

322334
/// Intern `ret`. This function assumes that `ret` references no other allocation.
323335
#[instrument(level = "debug", skip(ecx))]
324-
pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
336+
pub fn intern_const_alloc_for_constprop<'tcx, T: IsConstHeap, M: CompileTimeMachine<'tcx, T>>(
325337
ecx: &mut InterpCx<'tcx, M>,
326338
alloc_id: AllocId,
327339
) -> InterpResult<'tcx, ()> {

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ pub trait MayLeak: Copy {
4646
fn may_leak(self) -> bool;
4747
}
4848

49+
/// Whether this kind of memory is const heap (allocation that did not call `const_make_global`)
50+
pub trait IsConstHeap {
51+
fn is_const_heap(&self) -> bool;
52+
}
53+
4954
/// The functionality needed by memory to manage its allocations
5055
pub trait AllocMap<K: Hash + Eq, V> {
5156
/// Tests if the map contains the given key.

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
311311
interp_ok(new_ptr)
312312
}
313313

314+
pub fn leak_const_heap_ptr(
315+
&mut self,
316+
ptr: Pointer<Option<CtfeProvenance>>,
317+
) -> InterpResult<'tcx>
318+
where
319+
M: Machine<'tcx, Provenance = CtfeProvenance, AllocExtra = (), Bytes = Box<[u8]>>,
320+
{
321+
let (alloc_id, _, _) = self.ptr_get_alloc_id(ptr, 0)?;
322+
let Some((_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else {
323+
return Err(err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccess)))
324+
.into();
325+
};
326+
alloc.mutability = Mutability::Not;
327+
let alloc = self.tcx.mk_const_alloc(alloc);
328+
self.tcx.set_alloc_id_memory(alloc_id, alloc);
329+
interp_ok(())
330+
}
331+
314332
#[instrument(skip(self), level = "debug")]
315333
pub fn deallocate_ptr(
316334
&mut self,

compiler/rustc_const_eval/src/interpret/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ pub use self::intern::{
2929
HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop,
3030
intern_const_alloc_recursive,
3131
};
32-
pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
32+
pub use self::machine::{
33+
AllocMap, IsConstHeap, Machine, MayLeak, ReturnAction, compile_time_machine,
34+
};
3335
pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
3436
use self::operand::Operand;
3537
pub use self::operand::{ImmTy, Immediate, OpTy};

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ pub(crate) fn check_intrinsic_type(
415415
vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
416416
tcx.types.unit,
417417
),
418+
sym::const_make_global => (
419+
0,
420+
0,
421+
vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
422+
Ty::new_imm_ptr(tcx, tcx.types.u8),
423+
),
418424

419425
sym::ptr_offset_from => (
420426
1,

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@ symbols! {
714714
const_indexing,
715715
const_let,
716716
const_loop,
717+
const_make_global,
717718
const_mut_refs,
718719
const_panic,
719720
const_panic_fmt,

0 commit comments

Comments
 (0)