Skip to content

Commit c5ec462

Browse files
fee1-deadRalfJungoli-obk
committed
add const_make_global; err for const_allocate ptrs if didn't call
Co-Authored-By: Ralf Jung <post@ralfj.de> Co-Authored-By: Oli Scherer <github333195615777966@oli-obk.de>
1 parent 8df4a58 commit c5ec462

31 files changed

+361
-30
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ 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_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc}
63+
64+
const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}
65+
66+
const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr}
67+
68+
const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object
69+
5970
const_eval_copy_nonoverlapping_overlapping =
6071
`copy_nonoverlapping` called on overlapping ranges
6172

compiler/rustc_const_eval/src/const_eval/error.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::mem;
22

33
use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg};
44
use rustc_middle::mir::AssertKind;
5-
use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
5+
use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo};
66
use rustc_middle::query::TyCtxtAt;
77
use rustc_middle::ty::layout::LayoutError;
88
use rustc_middle::ty::{ConstInt, TyCtxt};
@@ -22,8 +22,22 @@ pub enum ConstEvalErrKind {
2222
ModifiedGlobal,
2323
RecursiveStatic,
2424
AssertFailure(AssertKind<ConstInt>),
25-
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
25+
Panic {
26+
msg: Symbol,
27+
line: u32,
28+
col: u32,
29+
file: Symbol,
30+
},
2631
WriteThroughImmutablePointer,
32+
/// Called `const_make_global` twice.
33+
ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId),
34+
/// Called `const_make_global` on a non-heap pointer.
35+
ConstMakeGlobalPtrIsNonHeap(String),
36+
/// Called `const_make_global` on a dangling pointer.
37+
ConstMakeGlobalWithDanglingPtr(String),
38+
/// Called `const_make_global` on a pointer that does not start at the
39+
/// beginning of an object.
40+
ConstMakeGlobalWithOffset(String),
2741
}
2842

2943
impl MachineStopType for ConstEvalErrKind {
@@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind {
3852
RecursiveStatic => const_eval_recursive_static,
3953
AssertFailure(x) => x.diagnostic_message(),
4054
WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer,
55+
ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
56+
const_eval_const_make_global_ptr_already_made_global
57+
}
58+
ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap,
59+
ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr,
60+
ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset,
4161
}
4262
}
4363
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
@@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind {
5171
Panic { msg, .. } => {
5272
adder("msg".into(), msg.into_diag_arg(&mut None));
5373
}
74+
ConstMakeGlobalPtrIsNonHeap(ptr)
75+
| ConstMakeGlobalWithOffset(ptr)
76+
| ConstMakeGlobalWithDanglingPtr(ptr) => {
77+
adder("ptr".into(), ptr.into_diag_arg(&mut None));
78+
}
79+
ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => {
80+
adder("alloc".into(), alloc.into_diag_arg(&mut None));
81+
}
5482
}
5583
}
5684
}

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: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,15 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
169169

170170
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
171171
pub enum MemoryKind {
172-
Heap,
172+
Heap { was_made_global: bool },
173173
}
174174

175175
impl fmt::Display for MemoryKind {
176176
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177177
match self {
178-
MemoryKind::Heap => write!(f, "heap allocation"),
178+
MemoryKind::Heap { was_made_global } => {
179+
write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" })
180+
}
179181
}
180182
}
181183
}
@@ -184,7 +186,7 @@ impl interpret::MayLeak for MemoryKind {
184186
#[inline(always)]
185187
fn may_leak(self) -> bool {
186188
match self {
187-
MemoryKind::Heap => false,
189+
MemoryKind::Heap { was_made_global } => was_made_global,
188190
}
189191
}
190192
}
@@ -420,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
420422
let ptr = ecx.allocate_ptr(
421423
Size::from_bytes(size),
422424
align,
423-
interpret::MemoryKind::Machine(MemoryKind::Heap),
425+
interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
424426
AllocInit::Uninit,
425427
)?;
426428
ecx.write_pointer(ptr, dest)?;
@@ -453,10 +455,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
453455
ecx.deallocate_ptr(
454456
ptr,
455457
Some((size, align)),
456-
interpret::MemoryKind::Machine(MemoryKind::Heap),
458+
interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
457459
)?;
458460
}
459461
}
462+
463+
sym::const_make_global => {
464+
let ptr = ecx.read_pointer(&args[0])?;
465+
ecx.make_const_heap_ptr_global(ptr)?;
466+
ecx.write_pointer(ptr, dest)?;
467+
}
468+
460469
// The intrinsic represents whether the value is known to the optimizer (LLVM).
461470
// We're not doing any optimizations here, so there is no optimizer that could know the value.
462471
// (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: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use super::{
3131
};
3232
use crate::const_eval;
3333
use crate::const_eval::DummyMachine;
34-
use crate::errors::NestedStaticInThreadLocal;
34+
use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal};
3535

3636
pub trait CompileTimeMachine<'tcx, T> = Machine<
3737
'tcx,
@@ -55,14 +55,43 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
5555
}
5656
}
5757

58+
pub enum DisallowInternReason {
59+
ConstHeap,
60+
}
61+
62+
/// A trait for controlling whether memory allocated in the interpreter can be interned.
63+
///
64+
/// This prevents us from interning `const_allocate` pointers that have not been made
65+
/// global through `const_make_global`.
66+
pub trait CanIntern {
67+
fn disallows_intern(&self) -> Option<DisallowInternReason>;
68+
}
69+
70+
impl CanIntern for const_eval::MemoryKind {
71+
fn disallows_intern(&self) -> Option<DisallowInternReason> {
72+
match self {
73+
const_eval::MemoryKind::Heap { was_made_global: false } => {
74+
Some(DisallowInternReason::ConstHeap)
75+
}
76+
const_eval::MemoryKind::Heap { was_made_global: true } => None,
77+
}
78+
}
79+
}
80+
81+
impl CanIntern for ! {
82+
fn disallows_intern(&self) -> Option<DisallowInternReason> {
83+
*self
84+
}
85+
}
86+
5887
/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
5988
///
6089
/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
6190
/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be*
6291
/// already mutable (as a sanity check).
6392
///
6493
/// Returns an iterator over all relocations referred to by this allocation.
65-
fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
94+
fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>(
6695
ecx: &mut InterpCx<'tcx, M>,
6796
alloc_id: AllocId,
6897
mutability: Mutability,
@@ -71,9 +100,26 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
71100
trace!("intern_shallow {:?}", alloc_id);
72101
// remove allocation
73102
// FIXME(#120456) - is `swap_remove` correct?
74-
let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
103+
let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
75104
return Err(());
76105
};
106+
107+
match kind {
108+
MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason {
109+
// attempting to intern a `const_allocate`d pointer that was not made global via
110+
// `const_make_global`. We emit an error here but don't return an `Err`. The `Err`
111+
// is for pointers that we can't intern at all (i.e. dangling pointers). We still
112+
// (recursively) intern this pointer because we don't have to worry about the
113+
// additional paperwork involved with _not_ interning it, such as storing it in
114+
// the dead memory map and having to deal with additional "dangling pointer"
115+
// messages if someone tries to store the non-made-global ptr in the final value.
116+
DisallowInternReason::ConstHeap => {
117+
ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span });
118+
}
119+
},
120+
MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {}
121+
}
122+
77123
// Set allocation mutability as appropriate. This is used by LLVM to put things into
78124
// read-only memory, and also by Miri when evaluating other globals that
79125
// access this one.
@@ -99,7 +145,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
99145
} else {
100146
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
101147
}
102-
Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
148+
Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov))
103149
}
104150

105151
/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
@@ -181,7 +227,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
181227
}
182228
InternKind::Static(Mutability::Not) => {
183229
(
184-
// Outermost allocation is mutable if `!Freeze`.
230+
// Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types.
185231
if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) {
186232
Mutability::Not
187233
} else {
@@ -321,7 +367,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
321367

322368
/// Intern `ret`. This function assumes that `ret` references no other allocation.
323369
#[instrument(level = "debug", skip(ecx))]
324-
pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
370+
pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>(
325371
ecx: &mut InterpCx<'tcx, M>,
326372
alloc_id: AllocId,
327373
) -> InterpResult<'tcx, ()> {

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use super::{
2626
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
2727
err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
2828
};
29+
use crate::const_eval::ConstEvalErrKind;
2930
use crate::fluent_generated as fluent;
3031

3132
#[derive(Debug, PartialEq, Copy, Clone)]
@@ -311,6 +312,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
311312
interp_ok(new_ptr)
312313
}
313314

315+
/// mark the `const_allocate`d pointer immutable so we can intern it.
316+
pub fn make_const_heap_ptr_global(
317+
&mut self,
318+
ptr: Pointer<Option<M::Provenance>>,
319+
) -> InterpResult<'tcx>
320+
where
321+
M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind>,
322+
{
323+
let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?;
324+
if offset.bytes() != 0 {
325+
return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(format!("{ptr:?}"))).into();
326+
}
327+
328+
let not_local_heap =
329+
matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_)));
330+
331+
if not_local_heap {
332+
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))).into();
333+
}
334+
335+
let (kind, alloc) = self.memory.alloc_map.get_mut_or(alloc_id, || {
336+
Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(format!("{ptr:?}")))
337+
})?;
338+
339+
alloc.mutability = Mutability::Not;
340+
341+
match kind {
342+
MemoryKind::Stack | MemoryKind::CallerLocation => {
343+
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}")))
344+
.into();
345+
}
346+
MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => {
347+
if *was_made_global {
348+
return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id))
349+
.into();
350+
}
351+
*was_made_global = true;
352+
}
353+
}
354+
355+
interp_ok(())
356+
}
357+
314358
#[instrument(skip(self), level = "debug")]
315359
pub fn deallocate_ptr(
316360
&mut self,

compiler/rustc_const_eval/src/util/check_validity_requirement.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ fn check_validity_requirement_strict<'tcx>(
5252

5353
let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine);
5454

55-
let allocated = cx
56-
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
57-
.expect("OOM: failed to allocate for uninit check");
55+
let allocated =
56+
cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check");
5857

5958
if kind == ValidityRequirement::Zero {
6059
cx.write_bytes_ptr(
@@ -185,7 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>(
185184
bug!("could not compute layout of {scalar:?}:{ty:?}")
186185
};
187186
let allocated = cx
188-
.allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
187+
.allocate(
188+
layout,
189+
MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global: false }),
190+
)
189191
.expect("OOM: failed to allocate for uninit check");
190192

191193
cx.write_scalar(scalar, &allocated).unwrap();

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ 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, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8))
420+
}
418421

419422
sym::ptr_offset_from => (
420423
1,

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> {
257257
/// Details of why a pointer had to be in-bounds.
258258
#[derive(Debug, Copy, Clone)]
259259
pub enum CheckInAllocMsg {
260-
/// We are access memory.
260+
/// We are accessing memory.
261261
MemoryAccess,
262262
/// We are doing pointer arithmetic.
263263
InboundsPointerArithmetic,

0 commit comments

Comments
 (0)