@@ -14,6 +14,7 @@ use std::ptr;
1414
1515use rustc_ast:: ast:: Mutability ;
1616use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
17+ use rustc_hir:: def_id:: DefId ;
1718use rustc_middle:: ty:: { self , Instance , ParamEnv , TyCtxt } ;
1819use rustc_target:: abi:: { Align , HasDataLayout , Size , TargetDataLayout } ;
1920
@@ -118,6 +119,17 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
118119 pub tcx : TyCtxt < ' tcx > ,
119120}
120121
122+ /// Return the `tcx` allocation containing the initial value of the given static
123+ pub fn get_static ( tcx : TyCtxt < ' tcx > , def_id : DefId ) -> InterpResult < ' tcx , & ' tcx Allocation > {
124+ trace ! ( "get_static: Need to compute {:?}" , def_id) ;
125+ let instance = Instance :: mono ( tcx, def_id) ;
126+ let gid = GlobalId { instance, promoted : None } ;
127+ // Use the raw query here to break validation cycles. Later uses of the static
128+ // will call the full query anyway.
129+ let raw_const = tcx. const_eval_raw ( ty:: ParamEnv :: reveal_all ( ) . and ( gid) ) ?;
130+ Ok ( tcx. global_alloc ( raw_const. alloc_id ) . unwrap_memory ( ) )
131+ }
132+
121133impl < ' mir , ' tcx , M : Machine < ' mir , ' tcx > > HasDataLayout for Memory < ' mir , ' tcx , M > {
122134 #[ inline]
123135 fn data_layout ( & self ) -> & TargetDataLayout {
@@ -137,15 +149,36 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
137149 }
138150
139151 /// Call this to turn untagged "global" pointers (obtained via `tcx`) into
140- /// the *canonical* machine pointer to the allocation. Must never be used
141- /// for any other pointers!
152+ /// the machine pointer to the allocation. Must never be used
153+ /// for any other pointers, nor for TLS statics.
154+ ///
155+ /// Using the resulting pointer represents a *direct* access to that memory
156+ /// (e.g. by directly using a `static`),
157+ /// as opposed to access through a pointer that was created by the program.
142158 ///
143- /// This represents a *direct* access to that memory, as opposed to access
144- /// through a pointer that was created by the program.
159+ /// This function can fail only if `ptr` points to an `extern static`.
145160 #[ inline]
146- pub fn tag_global_base_pointer ( & self , ptr : Pointer ) -> Pointer < M :: PointerTag > {
147- let id = M :: canonical_alloc_id ( self , ptr. alloc_id ) ;
148- ptr. with_tag ( M :: tag_global_base_pointer ( & self . extra , id) )
161+ pub fn global_base_pointer (
162+ & self ,
163+ mut ptr : Pointer ,
164+ ) -> InterpResult < ' tcx , Pointer < M :: PointerTag > > {
165+ // We need to handle `extern static`.
166+ let ptr = match self . tcx . get_global_alloc ( ptr. alloc_id ) {
167+ Some ( GlobalAlloc :: Static ( def_id) ) if self . tcx . is_thread_local_static ( def_id) => {
168+ bug ! ( "global memory cannot point to thread-local static" )
169+ }
170+ Some ( GlobalAlloc :: Static ( def_id) ) if self . tcx . is_foreign_item ( def_id) => {
171+ ptr. alloc_id = M :: extern_static_alloc_id ( self , def_id) ?;
172+ ptr
173+ }
174+ _ => {
175+ // No need to change the `AllocId`.
176+ ptr
177+ }
178+ } ;
179+ // And we need to get the tag.
180+ let tag = M :: tag_global_base_pointer ( & self . extra , ptr. alloc_id ) ;
181+ Ok ( ptr. with_tag ( tag) )
149182 }
150183
151184 pub fn create_fn_alloc (
@@ -162,7 +195,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
162195 id
163196 }
164197 } ;
165- self . tag_global_base_pointer ( Pointer :: from ( id) )
198+ // Functions are global allocations, so make sure we get the right base pointer.
199+ // We know this is not an `extern static` so this cannot fail.
200+ self . global_base_pointer ( Pointer :: from ( id) ) . unwrap ( )
166201 }
167202
168203 pub fn allocate (
@@ -195,6 +230,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
195230 M :: GLOBAL_KIND . map( MemoryKind :: Machine ) ,
196231 "dynamically allocating global memory"
197232 ) ;
233+ // This is a new allocation, not a new global one, so no `global_base_ptr`.
198234 let ( alloc, tag) = M :: init_allocation_extra ( & self . extra , id, Cow :: Owned ( alloc) , Some ( kind) ) ;
199235 self . alloc_map . insert ( id, ( kind, alloc. into_owned ( ) ) ) ;
200236 Pointer :: from ( id) . with_tag ( tag)
@@ -437,6 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
437473 Some ( GlobalAlloc :: Function ( ..) ) => throw_ub ! ( DerefFunctionPointer ( id) ) ,
438474 None => throw_ub ! ( PointerUseAfterFree ( id) ) ,
439475 Some ( GlobalAlloc :: Static ( def_id) ) => {
476+ assert ! ( tcx. is_static( def_id) ) ;
440477 assert ! ( !tcx. is_thread_local_static( def_id) ) ;
441478 // Notice that every static has two `AllocId` that will resolve to the same
442479 // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID,
@@ -448,29 +485,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
448485 // The `GlobalAlloc::Memory` branch here is still reachable though; when a static
449486 // contains a reference to memory that was created during its evaluation (i.e., not
450487 // to another static), those inner references only exist in "resolved" form.
451- //
452- // Assumes `id` is already canonical.
453488 if tcx. is_foreign_item ( def_id) {
454- trace ! ( "get_global_alloc: foreign item {:?}" , def_id) ;
455- throw_unsup ! ( ReadForeignStatic ( def_id) )
489+ throw_unsup ! ( ReadExternStatic ( def_id) ) ;
456490 }
457- trace ! ( "get_global_alloc: Need to compute {:?}" , def_id) ;
458- let instance = Instance :: mono ( tcx, def_id) ;
459- let gid = GlobalId { instance, promoted : None } ;
460- // Use the raw query here to break validation cycles. Later uses of the static
461- // will call the full query anyway.
462- let raw_const =
463- tcx. const_eval_raw ( ty:: ParamEnv :: reveal_all ( ) . and ( gid) ) . map_err ( |err| {
464- // no need to report anything, the const_eval call takes care of that
465- // for statics
466- assert ! ( tcx. is_static( def_id) ) ;
467- err
468- } ) ?;
469- // Make sure we use the ID of the resolved memory, not the lazy one!
470- let id = raw_const. alloc_id ;
471- let allocation = tcx. global_alloc ( id) . unwrap_memory ( ) ;
472-
473- ( allocation, Some ( def_id) )
491+
492+ ( get_static ( tcx, def_id) ?, Some ( def_id) )
474493 }
475494 } ;
476495 M :: before_access_global ( memory_extra, id, alloc, def_id, is_write) ?;
@@ -482,6 +501,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
482501 alloc,
483502 M :: GLOBAL_KIND . map ( MemoryKind :: Machine ) ,
484503 ) ;
504+ // Sanity check that this is the same pointer we would have gotten via `global_base_pointer`.
485505 debug_assert_eq ! ( tag, M :: tag_global_base_pointer( memory_extra, id) ) ;
486506 Ok ( alloc)
487507 }
@@ -492,7 +512,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
492512 & self ,
493513 id : AllocId ,
494514 ) -> InterpResult < ' tcx , & Allocation < M :: PointerTag , M :: AllocExtra > > {
495- let id = M :: canonical_alloc_id ( self , id) ;
496515 // The error type of the inner closure here is somewhat funny. We have two
497516 // ways of "erroring": An actual error, or because we got a reference from
498517 // `get_global_alloc` that we can actually use directly without inserting anything anywhere.
@@ -529,7 +548,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
529548 & mut self ,
530549 id : AllocId ,
531550 ) -> InterpResult < ' tcx , & mut Allocation < M :: PointerTag , M :: AllocExtra > > {
532- let id = M :: canonical_alloc_id ( self , id) ;
533551 let tcx = self . tcx ;
534552 let memory_extra = & self . extra ;
535553 let a = self . alloc_map . get_mut_or ( id, || {
@@ -568,7 +586,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
568586 id : AllocId ,
569587 liveness : AllocCheck ,
570588 ) -> InterpResult < ' static , ( Size , Align ) > {
571- let id = M :: canonical_alloc_id ( self , id) ;
572589 // # Regular allocations
573590 // Don't use `self.get_raw` here as that will
574591 // a) cause cycles in case `id` refers to a static
@@ -621,7 +638,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
621638 }
622639 }
623640
624- /// Assumes `id` is already canonical.
625641 fn get_fn_alloc ( & self , id : AllocId ) -> Option < FnVal < ' tcx , M :: ExtraFnVal > > {
626642 trace ! ( "reading fn ptr: {}" , id) ;
627643 if let Some ( extra) = self . extra_fn_ptr_map . get ( & id) {
@@ -642,8 +658,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
642658 if ptr. offset . bytes ( ) != 0 {
643659 throw_ub ! ( InvalidFunctionPointer ( ptr. erase_tag( ) ) )
644660 }
645- let id = M :: canonical_alloc_id ( self , ptr. alloc_id ) ;
646- self . get_fn_alloc ( id ) . ok_or_else ( || err_ub ! ( InvalidFunctionPointer ( ptr. erase_tag( ) ) ) . into ( ) )
661+ self . get_fn_alloc ( ptr. alloc_id )
662+ . ok_or_else ( || err_ub ! ( InvalidFunctionPointer ( ptr. erase_tag( ) ) ) . into ( ) )
647663 }
648664
649665 pub fn mark_immutable ( & mut self , id : AllocId ) -> InterpResult < ' tcx > {
0 commit comments