@@ -137,15 +137,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
137137 }
138138
139139 /// 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!
140+ /// the machine pointer to the allocation. Must never be used
141+ /// for any other pointers, nor for TLS statics.
142142 ///
143- /// This represents a *direct* access to that memory, as opposed to access
144- /// through a pointer that was created by the program.
143+ /// Using the resulting pointer represents a *direct* access to that memory
144+ /// (e.g. by directly using a `static`),
145+ /// as opposed to access through a pointer that was created by the program.
146+ ///
147+ /// This function can fail only if `ptr` points to an `extern static`.
145148 #[ 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) )
149+ pub fn global_base_pointer ( & self , mut ptr : Pointer ) -> InterpResult < ' tcx , Pointer < M :: PointerTag > > {
150+ // We need to handle `extern static`.
151+ let ptr = match self . tcx . get_global_alloc ( ptr. alloc_id ) {
152+ Some ( GlobalAlloc :: Static ( def_id) ) if self . tcx . is_thread_local_static ( def_id) => {
153+ bug ! ( "global memory cannot point to thread-local static" )
154+ }
155+ Some ( GlobalAlloc :: Static ( def_id) ) if self . tcx . is_foreign_item ( def_id) => {
156+ ptr. alloc_id = M :: extern_static_alloc_id ( self , def_id) ?;
157+ ptr
158+ }
159+ _ => {
160+ // No need to change the `AllocId`.
161+ ptr
162+ }
163+ } ;
164+ // And we need to get the tag.
165+ let tag = M :: tag_global_base_pointer ( & self . extra , ptr. alloc_id ) ;
166+ Ok ( ptr. with_tag ( tag) )
149167 }
150168
151169 pub fn create_fn_alloc (
@@ -162,7 +180,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
162180 id
163181 }
164182 } ;
165- self . tag_global_base_pointer ( Pointer :: from ( id) )
183+ // Functions are global allocations, so make sure we get the right base pointer.
184+ // We know this is not an `extern static` so this cannmot fail.
185+ self . global_base_pointer ( Pointer :: from ( id) ) . unwrap ( )
166186 }
167187
168188 pub fn allocate (
@@ -195,6 +215,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
195215 M :: GLOBAL_KIND . map( MemoryKind :: Machine ) ,
196216 "dynamically allocating global memory"
197217 ) ;
218+ // This is a new allocation, not a new global one, so no `global_base_ptr`.
198219 let ( alloc, tag) = M :: init_allocation_extra ( & self . extra , id, Cow :: Owned ( alloc) , Some ( kind) ) ;
199220 self . alloc_map . insert ( id, ( kind, alloc. into_owned ( ) ) ) ;
200221 Pointer :: from ( id) . with_tag ( tag)
@@ -437,6 +458,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
437458 Some ( GlobalAlloc :: Function ( ..) ) => throw_ub ! ( DerefFunctionPointer ( id) ) ,
438459 None => throw_ub ! ( PointerUseAfterFree ( id) ) ,
439460 Some ( GlobalAlloc :: Static ( def_id) ) => {
461+ assert ! ( tcx. is_static( def_id) ) ;
440462 assert ! ( !tcx. is_thread_local_static( def_id) ) ;
441463 // Notice that every static has two `AllocId` that will resolve to the same
442464 // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID,
@@ -448,24 +470,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
448470 // The `GlobalAlloc::Memory` branch here is still reachable though; when a static
449471 // contains a reference to memory that was created during its evaluation (i.e., not
450472 // to another static), those inner references only exist in "resolved" form.
451- //
452- // Assumes `id` is already canonical.
453473 if tcx. is_foreign_item ( def_id) {
454- trace ! ( "get_global_alloc: foreign item {:?}" , def_id) ;
455- throw_unsup ! ( ReadForeignStatic ( def_id) )
474+ throw_unsup ! ( ReadExternStatic ( def_id) ) ;
456475 }
457476 trace ! ( "get_global_alloc: Need to compute {:?}" , def_id) ;
458477 let instance = Instance :: mono ( tcx, def_id) ;
459478 let gid = GlobalId { instance, promoted : None } ;
460479 // Use the raw query here to break validation cycles. Later uses of the static
461480 // 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- } ) ?;
481+ let raw_const = tcx. const_eval_raw ( ty:: ParamEnv :: reveal_all ( ) . and ( gid) ) ?;
469482 // Make sure we use the ID of the resolved memory, not the lazy one!
470483 let id = raw_const. alloc_id ;
471484 let allocation = tcx. global_alloc ( id) . unwrap_memory ( ) ;
@@ -482,6 +495,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
482495 alloc,
483496 M :: GLOBAL_KIND . map ( MemoryKind :: Machine ) ,
484497 ) ;
498+ // Sanity check that this is the same pointer we would have gotten via `global_base_pointer`.
485499 debug_assert_eq ! ( tag, M :: tag_global_base_pointer( memory_extra, id) ) ;
486500 Ok ( alloc)
487501 }
@@ -492,7 +506,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
492506 & self ,
493507 id : AllocId ,
494508 ) -> InterpResult < ' tcx , & Allocation < M :: PointerTag , M :: AllocExtra > > {
495- let id = M :: canonical_alloc_id ( self , id) ;
496509 // The error type of the inner closure here is somewhat funny. We have two
497510 // ways of "erroring": An actual error, or because we got a reference from
498511 // `get_global_alloc` that we can actually use directly without inserting anything anywhere.
@@ -529,7 +542,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
529542 & mut self ,
530543 id : AllocId ,
531544 ) -> InterpResult < ' tcx , & mut Allocation < M :: PointerTag , M :: AllocExtra > > {
532- let id = M :: canonical_alloc_id ( self , id) ;
533545 let tcx = self . tcx ;
534546 let memory_extra = & self . extra ;
535547 let a = self . alloc_map . get_mut_or ( id, || {
@@ -568,7 +580,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
568580 id : AllocId ,
569581 liveness : AllocCheck ,
570582 ) -> InterpResult < ' static , ( Size , Align ) > {
571- let id = M :: canonical_alloc_id ( self , id) ;
572583 // # Regular allocations
573584 // Don't use `self.get_raw` here as that will
574585 // a) cause cycles in case `id` refers to a static
@@ -621,7 +632,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
621632 }
622633 }
623634
624- /// Assumes `id` is already canonical.
625635 fn get_fn_alloc ( & self , id : AllocId ) -> Option < FnVal < ' tcx , M :: ExtraFnVal > > {
626636 trace ! ( "reading fn ptr: {}" , id) ;
627637 if let Some ( extra) = self . extra_fn_ptr_map . get ( & id) {
@@ -642,8 +652,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
642652 if ptr. offset . bytes ( ) != 0 {
643653 throw_ub ! ( InvalidFunctionPointer ( ptr. erase_tag( ) ) )
644654 }
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 ( ) )
655+ self . get_fn_alloc ( ptr. alloc_id ) . ok_or_else ( || err_ub ! ( InvalidFunctionPointer ( ptr. erase_tag( ) ) ) . into ( ) )
647656 }
648657
649658 pub fn mark_immutable ( & mut self , id : AllocId ) -> InterpResult < ' tcx > {
0 commit comments