@@ -14,6 +14,7 @@ use std::ptr;
14
14
15
15
use rustc_ast:: ast:: Mutability ;
16
16
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
17
+ use rustc_hir:: def_id:: DefId ;
17
18
use rustc_middle:: ty:: { self , Instance , ParamEnv , TyCtxt } ;
18
19
use rustc_target:: abi:: { Align , HasDataLayout , Size , TargetDataLayout } ;
19
20
@@ -118,6 +119,17 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
118
119
pub tcx : TyCtxt < ' tcx > ,
119
120
}
120
121
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
+
121
133
impl < ' mir , ' tcx , M : Machine < ' mir , ' tcx > > HasDataLayout for Memory < ' mir , ' tcx , M > {
122
134
#[ inline]
123
135
fn data_layout ( & self ) -> & TargetDataLayout {
@@ -137,15 +149,36 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
137
149
}
138
150
139
151
/// 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.
142
158
///
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`.
145
160
#[ 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) )
149
182
}
150
183
151
184
pub fn create_fn_alloc (
@@ -162,7 +195,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
162
195
id
163
196
}
164
197
} ;
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 ( )
166
201
}
167
202
168
203
pub fn allocate (
@@ -195,6 +230,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
195
230
M :: GLOBAL_KIND . map( MemoryKind :: Machine ) ,
196
231
"dynamically allocating global memory"
197
232
) ;
233
+ // This is a new allocation, not a new global one, so no `global_base_ptr`.
198
234
let ( alloc, tag) = M :: init_allocation_extra ( & self . extra , id, Cow :: Owned ( alloc) , Some ( kind) ) ;
199
235
self . alloc_map . insert ( id, ( kind, alloc. into_owned ( ) ) ) ;
200
236
Pointer :: from ( id) . with_tag ( tag)
@@ -437,6 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
437
473
Some ( GlobalAlloc :: Function ( ..) ) => throw_ub ! ( DerefFunctionPointer ( id) ) ,
438
474
None => throw_ub ! ( PointerUseAfterFree ( id) ) ,
439
475
Some ( GlobalAlloc :: Static ( def_id) ) => {
476
+ assert ! ( tcx. is_static( def_id) ) ;
440
477
assert ! ( !tcx. is_thread_local_static( def_id) ) ;
441
478
// Notice that every static has two `AllocId` that will resolve to the same
442
479
// 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> {
448
485
// The `GlobalAlloc::Memory` branch here is still reachable though; when a static
449
486
// contains a reference to memory that was created during its evaluation (i.e., not
450
487
// to another static), those inner references only exist in "resolved" form.
451
- //
452
- // Assumes `id` is already canonical.
453
488
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) ) ;
456
490
}
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) )
474
493
}
475
494
} ;
476
495
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> {
482
501
alloc,
483
502
M :: GLOBAL_KIND . map ( MemoryKind :: Machine ) ,
484
503
) ;
504
+ // Sanity check that this is the same pointer we would have gotten via `global_base_pointer`.
485
505
debug_assert_eq ! ( tag, M :: tag_global_base_pointer( memory_extra, id) ) ;
486
506
Ok ( alloc)
487
507
}
@@ -492,7 +512,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
492
512
& self ,
493
513
id : AllocId ,
494
514
) -> InterpResult < ' tcx , & Allocation < M :: PointerTag , M :: AllocExtra > > {
495
- let id = M :: canonical_alloc_id ( self , id) ;
496
515
// The error type of the inner closure here is somewhat funny. We have two
497
516
// ways of "erroring": An actual error, or because we got a reference from
498
517
// `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> {
529
548
& mut self ,
530
549
id : AllocId ,
531
550
) -> InterpResult < ' tcx , & mut Allocation < M :: PointerTag , M :: AllocExtra > > {
532
- let id = M :: canonical_alloc_id ( self , id) ;
533
551
let tcx = self . tcx ;
534
552
let memory_extra = & self . extra ;
535
553
let a = self . alloc_map . get_mut_or ( id, || {
@@ -568,7 +586,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
568
586
id : AllocId ,
569
587
liveness : AllocCheck ,
570
588
) -> InterpResult < ' static , ( Size , Align ) > {
571
- let id = M :: canonical_alloc_id ( self , id) ;
572
589
// # Regular allocations
573
590
// Don't use `self.get_raw` here as that will
574
591
// 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> {
621
638
}
622
639
}
623
640
624
- /// Assumes `id` is already canonical.
625
641
fn get_fn_alloc ( & self , id : AllocId ) -> Option < FnVal < ' tcx , M :: ExtraFnVal > > {
626
642
trace ! ( "reading fn ptr: {}" , id) ;
627
643
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> {
642
658
if ptr. offset . bytes ( ) != 0 {
643
659
throw_ub ! ( InvalidFunctionPointer ( ptr. erase_tag( ) ) )
644
660
}
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 ( ) )
647
663
}
648
664
649
665
pub fn mark_immutable ( & mut self , id : AllocId ) -> InterpResult < ' tcx > {
0 commit comments