Skip to content

Commit 1cf090e

Browse files
committed
Auto merge of #69408 - RalfJung:canonical-alloc-id, r=oli-obk
Miri: let machine canonicalize AllocIDs This implements the rustc side of the plan I laid out [here](rust-lang/miri#1147 (comment)). Miri PR: rust-lang/miri#1190
2 parents beac68a + 9b62d60 commit 1cf090e

File tree

4 files changed

+58
-66
lines changed

4 files changed

+58
-66
lines changed

src/librustc_mir/const_eval/machine.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use rustc::mir;
22
use rustc::ty::layout::HasTyCtxt;
3-
use rustc::ty::{self, Ty, TyCtxt};
4-
use rustc_hir::def_id::DefId;
3+
use rustc::ty::{self, Ty};
54
use std::borrow::{Borrow, Cow};
65
use std::collections::hash_map::Entry;
76
use std::hash::Hash;
@@ -320,13 +319,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
320319
Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
321320
}
322321

323-
fn find_foreign_static(
324-
_tcx: TyCtxt<'tcx>,
325-
_def_id: DefId,
326-
) -> InterpResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
327-
throw_unsup!(ReadForeignStatic)
328-
}
329-
330322
#[inline(always)]
331323
fn init_allocation_extra<'b>(
332324
_memory_extra: &MemoryExtra,

src/librustc_mir/interpret/machine.rs

+24-19
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ use std::borrow::{Borrow, Cow};
66
use std::hash::Hash;
77

88
use rustc::mir;
9-
use rustc::ty::{self, Ty, TyCtxt};
10-
use rustc_hir::def_id::DefId;
9+
use rustc::ty::{self, Ty};
1110
use rustc_span::Span;
1211

1312
use super::{
@@ -123,10 +122,6 @@ pub trait Machine<'mir, 'tcx>: Sized {
123122
/// Whether to enforce the validity invariant
124123
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
125124

126-
/// Called before a basic block terminator is executed.
127-
/// You can use this to detect endlessly running programs.
128-
fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
129-
130125
/// Entry point to all function calls.
131126
///
132127
/// Returns either the mir to use for the call, or `None` if execution should
@@ -175,18 +170,6 @@ pub trait Machine<'mir, 'tcx>: Sized {
175170
unwind: Option<mir::BasicBlock>,
176171
) -> InterpResult<'tcx>;
177172

178-
/// Called for read access to a foreign static item.
179-
///
180-
/// This will only be called once per static and machine; the result is cached in
181-
/// the machine memory. (This relies on `AllocMap::get_or` being able to add the
182-
/// owned allocation to the map even when the map is shared.)
183-
///
184-
/// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
185-
fn find_foreign_static(
186-
tcx: TyCtxt<'tcx>,
187-
def_id: DefId,
188-
) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;
189-
190173
/// Called for all binary operations where the LHS has pointer type.
191174
///
192175
/// Returns a (value, overflowed) pair if the operation succeeded
@@ -204,6 +187,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
204187
) -> InterpResult<'tcx>;
205188

206189
/// Called to read the specified `local` from the `frame`.
190+
#[inline]
207191
fn access_local(
208192
_ecx: &InterpCx<'mir, 'tcx, Self>,
209193
frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
@@ -212,14 +196,33 @@ pub trait Machine<'mir, 'tcx>: Sized {
212196
frame.locals[local].access()
213197
}
214198

199+
/// Called before a basic block terminator is executed.
200+
/// You can use this to detect endlessly running programs.
201+
#[inline]
202+
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
203+
Ok(())
204+
}
205+
215206
/// Called before a `Static` value is accessed.
207+
#[inline]
216208
fn before_access_static(
217209
_memory_extra: &Self::MemoryExtra,
218210
_allocation: &Allocation,
219211
) -> InterpResult<'tcx> {
220212
Ok(())
221213
}
222214

215+
/// Called for *every* memory access to determine the real ID of the given allocation.
216+
/// This provides a way for the machine to "redirect" certain allocations as it sees fit.
217+
///
218+
/// This is used by Miri to redirect extern statics to real allocations.
219+
///
220+
/// This function must be idempotent.
221+
#[inline]
222+
fn canonical_alloc_id(_mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId {
223+
id
224+
}
225+
223226
/// Called to initialize the "extra" state of an allocation and make the pointers
224227
/// it contains (in relocations) tagged. The way we construct allocations is
225228
/// to always first construct it without extra and then add the extra.
@@ -247,6 +250,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
247250
/// Return the "base" tag for the given *static* allocation: the one that is used for direct
248251
/// accesses to this static/const/fn allocation. If `id` is not a static allocation,
249252
/// this will return an unusable tag (i.e., accesses will be UB)!
253+
///
254+
/// Expects `id` to be already canonical, if needed.
250255
fn tag_static_base_pointer(memory_extra: &Self::MemoryExtra, id: AllocId) -> Self::PointerTag;
251256

252257
/// Executes a retagging operation
@@ -259,7 +264,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
259264
Ok(())
260265
}
261266

262-
/// Called immediately before a new stack frame got pushed
267+
/// Called immediately before a new stack frame got pushed.
263268
fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>;
264269

265270
/// Called immediately after a stack frame gets popped

src/librustc_mir/interpret/memory.rs

+33-26
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
150150
/// through a pointer that was created by the program.
151151
#[inline]
152152
pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
153-
ptr.with_tag(M::tag_static_base_pointer(&self.extra, ptr.alloc_id))
153+
let id = M::canonical_alloc_id(self, ptr.alloc_id);
154+
ptr.with_tag(M::tag_static_base_pointer(&self.extra, id))
154155
}
155156

156157
pub fn create_fn_alloc(
@@ -421,6 +422,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
421422
/// The `GlobalAlloc::Memory` branch here is still reachable though; when a static
422423
/// contains a reference to memory that was created during its evaluation (i.e., not to
423424
/// another static), those inner references only exist in "resolved" form.
425+
///
426+
/// Assumes `id` is already canonical.
424427
fn get_static_alloc(
425428
memory_extra: &M::MemoryExtra,
426429
tcx: TyCtxtAt<'tcx>,
@@ -434,31 +437,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
434437
Some(GlobalAlloc::Static(def_id)) => {
435438
// We got a "lazy" static that has not been computed yet.
436439
if tcx.is_foreign_item(def_id) {
437-
trace!("static_alloc: foreign item {:?}", def_id);
438-
M::find_foreign_static(tcx.tcx, def_id)?
439-
} else {
440-
trace!("static_alloc: Need to compute {:?}", def_id);
441-
let instance = Instance::mono(tcx.tcx, def_id);
442-
let gid = GlobalId { instance, promoted: None };
443-
// use the raw query here to break validation cycles. Later uses of the static
444-
// will call the full query anyway
445-
let raw_const =
446-
tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
447-
// no need to report anything, the const_eval call takes care of that
448-
// for statics
449-
assert!(tcx.is_static(def_id));
450-
match err {
451-
ErrorHandled::Reported => err_inval!(ReferencedConstant),
452-
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
453-
}
454-
})?;
455-
// Make sure we use the ID of the resolved memory, not the lazy one!
456-
let id = raw_const.alloc_id;
457-
let allocation = tcx.alloc_map.lock().unwrap_memory(id);
458-
459-
M::before_access_static(memory_extra, allocation)?;
460-
Cow::Borrowed(allocation)
440+
trace!("get_static_alloc: foreign item {:?}", def_id);
441+
throw_unsup!(ReadForeignStatic)
461442
}
443+
trace!("get_static_alloc: Need to compute {:?}", def_id);
444+
let instance = Instance::mono(tcx.tcx, def_id);
445+
let gid = GlobalId { instance, promoted: None };
446+
// use the raw query here to break validation cycles. Later uses of the static
447+
// will call the full query anyway
448+
let raw_const =
449+
tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
450+
// no need to report anything, the const_eval call takes care of that
451+
// for statics
452+
assert!(tcx.is_static(def_id));
453+
match err {
454+
ErrorHandled::Reported => err_inval!(ReferencedConstant),
455+
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
456+
}
457+
})?;
458+
// Make sure we use the ID of the resolved memory, not the lazy one!
459+
let id = raw_const.alloc_id;
460+
let allocation = tcx.alloc_map.lock().unwrap_memory(id);
461+
462+
M::before_access_static(memory_extra, allocation)?;
463+
Cow::Borrowed(allocation)
462464
}
463465
};
464466
// We got tcx memory. Let the machine initialize its "extra" stuff.
@@ -478,6 +480,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
478480
&self,
479481
id: AllocId,
480482
) -> InterpResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> {
483+
let id = M::canonical_alloc_id(self, id);
481484
// The error type of the inner closure here is somewhat funny. We have two
482485
// ways of "erroring": An actual error, or because we got a reference from
483486
// `get_static_alloc` that we can actually use directly without inserting anything anywhere.
@@ -513,6 +516,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
513516
&mut self,
514517
id: AllocId,
515518
) -> InterpResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
519+
let id = M::canonical_alloc_id(self, id);
516520
let tcx = self.tcx;
517521
let memory_extra = &self.extra;
518522
let a = self.alloc_map.get_mut_or(id, || {
@@ -550,6 +554,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
550554
id: AllocId,
551555
liveness: AllocCheck,
552556
) -> InterpResult<'static, (Size, Align)> {
557+
let id = M::canonical_alloc_id(self, id);
553558
// # Regular allocations
554559
// Don't use `self.get_raw` here as that will
555560
// a) cause cycles in case `id` refers to a static
@@ -602,6 +607,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
602607
}
603608
}
604609

610+
/// Assumes `id` is already canonical.
605611
fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
606612
trace!("reading fn ptr: {}", id);
607613
if let Some(extra) = self.extra_fn_ptr_map.get(&id) {
@@ -622,7 +628,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
622628
if ptr.offset.bytes() != 0 {
623629
throw_unsup!(InvalidFunctionPointer)
624630
}
625-
self.get_fn_alloc(ptr.alloc_id).ok_or_else(|| err_unsup!(ExecuteMemory).into())
631+
let id = M::canonical_alloc_id(self, ptr.alloc_id);
632+
self.get_fn_alloc(id).ok_or_else(|| err_unsup!(ExecuteMemory).into())
626633
}
627634

628635
pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {

src/librustc_mir/transform/const_prop.rs

-12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use rustc::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
2323
use rustc_ast::ast::Mutability;
2424
use rustc_data_structures::fx::FxHashMap;
2525
use rustc_hir::def::DefKind;
26-
use rustc_hir::def_id::DefId;
2726
use rustc_hir::HirId;
2827
use rustc_index::vec::IndexVec;
2928
use rustc_infer::traits;
@@ -222,13 +221,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
222221
));
223222
}
224223

225-
fn find_foreign_static(
226-
_tcx: TyCtxt<'tcx>,
227-
_def_id: DefId,
228-
) -> InterpResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
229-
throw_unsup!(ReadForeignStatic)
230-
}
231-
232224
#[inline(always)]
233225
fn init_allocation_extra<'b>(
234226
_memory_extra: &(),
@@ -279,10 +271,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
279271
Ok(())
280272
}
281273

282-
fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
283-
Ok(())
284-
}
285-
286274
#[inline(always)]
287275
fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
288276
Ok(())

0 commit comments

Comments
 (0)