4
4
use std:: borrow:: Cow ;
5
5
use std:: cell:: RefCell ;
6
6
use std:: rc:: Rc ;
7
+ use std:: collections:: HashMap ;
7
8
8
9
use rand:: rngs:: StdRng ;
9
10
10
- use rustc_hir:: def_id:: DefId ;
11
11
use rustc:: mir;
12
12
use rustc:: ty:: {
13
13
self ,
14
14
layout:: { LayoutOf , Size } ,
15
- Ty , TyCtxt ,
15
+ Ty ,
16
16
} ;
17
17
use rustc_span:: { source_map:: Span , symbol:: sym} ;
18
18
use syntax:: attr;
@@ -73,7 +73,11 @@ pub struct MemoryExtra {
73
73
pub stacked_borrows : stacked_borrows:: MemoryExtra ,
74
74
pub intptrcast : intptrcast:: MemoryExtra ,
75
75
76
+ /// Mapping extern static names to their canonical allocation.
77
+ pub ( crate ) extern_statics : HashMap < & ' static str , AllocId > ,
78
+
76
79
/// The random number generator used for resolving non-determinism.
80
+ /// Needs to be queried by ptr_to_int, hence needs interior mutability.
77
81
pub ( crate ) rng : RefCell < StdRng > ,
78
82
79
83
/// Whether to enforce the validity invariant.
@@ -85,10 +89,30 @@ impl MemoryExtra {
85
89
MemoryExtra {
86
90
stacked_borrows : Rc :: new ( RefCell :: new ( GlobalState :: new ( tracked_pointer_tag) ) ) ,
87
91
intptrcast : Default :: default ( ) ,
92
+ extern_statics : HashMap :: default ( ) ,
88
93
rng : RefCell :: new ( rng) ,
89
94
validate,
90
95
}
91
96
}
97
+
98
+ /// Sets up the "extern statics" for this machine.
99
+ pub fn init_extern_statics < ' mir , ' tcx > ( this : & mut MiriEvalContext < ' mir , ' tcx > ) -> InterpResult < ' tcx > {
100
+ match this. tcx . sess . target . target . target_os . as_str ( ) {
101
+ "linux" => {
102
+ // "__cxa_thread_atexit_impl"
103
+ // This should be all-zero, pointer-sized.
104
+ let layout = this. layout_of ( this. tcx . types . usize ) ?;
105
+ let place = this. allocate ( layout, MiriMemoryKind :: Machine . into ( ) ) ;
106
+ this. write_scalar ( Scalar :: from_machine_usize ( 0 , & * this. tcx ) , place. into ( ) ) ?;
107
+ this. memory . extra . extern_statics . insert (
108
+ "__cxa_thread_atexit_impl" ,
109
+ place. ptr . assert_ptr ( ) . alloc_id ,
110
+ ) . unwrap_none ( ) ;
111
+ }
112
+ _ => { } // No "extern statics" supported on this platform
113
+ }
114
+ Ok ( ( ) )
115
+ }
92
116
}
93
117
94
118
/// The machine itself.
@@ -263,32 +287,32 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
263
287
Ok ( ( ) )
264
288
}
265
289
266
- fn find_foreign_static (
267
- tcx : TyCtxt < ' tcx > ,
268
- def_id : DefId ,
269
- ) -> InterpResult < ' tcx , Cow < ' tcx , Allocation > > {
290
+ fn canonical_alloc_id (
291
+ mem : & Memory < ' mir , ' tcx , Self > ,
292
+ id : AllocId ,
293
+ ) -> AllocId {
294
+ let tcx = mem. tcx ;
295
+ // Figure out if this is an extern static, and if yes, which one.
296
+ let def_id = match tcx. alloc_map . lock ( ) . get ( id) {
297
+ Some ( GlobalAlloc :: Static ( def_id) ) if tcx. is_foreign_item ( def_id) => def_id,
298
+ _ => {
299
+ // No need to canonicalize anything.
300
+ return id;
301
+ }
302
+ } ;
270
303
let attrs = tcx. get_attrs ( def_id) ;
271
304
let link_name = match attr:: first_attr_value_str_by_name ( & attrs, sym:: link_name) {
272
305
Some ( name) => name. as_str ( ) ,
273
306
None => tcx. item_name ( def_id) . as_str ( ) ,
274
307
} ;
275
-
276
- let alloc = match & * link_name {
277
- "__cxa_thread_atexit_impl" => {
278
- // This should be all-zero, pointer-sized.
279
- let size = tcx. data_layout . pointer_size ;
280
- let data = vec ! [ 0 ; size. bytes( ) as usize ] ;
281
- Allocation :: from_bytes ( & data, tcx. data_layout . pointer_align . abi )
282
- }
283
- _ => throw_unsup_format ! ( "can't access foreign static: {}" , link_name) ,
284
- } ;
285
- Ok ( Cow :: Owned ( alloc) )
286
- }
287
-
288
- #[ inline( always) ]
289
- fn before_terminator ( _ecx : & mut InterpCx < ' mir , ' tcx , Self > ) -> InterpResult < ' tcx > {
290
- // We are not interested in detecting loops.
291
- Ok ( ( ) )
308
+ // Check if we know this one.
309
+ if let Some ( canonical_id) = mem. extra . extern_statics . get ( & * link_name) {
310
+ trace ! ( "canonical_alloc_id: {:?} ({}) -> {:?}" , id, link_name, canonical_id) ;
311
+ * canonical_id
312
+ } else {
313
+ // Return original id; `Memory::get_static_alloc` will throw an error.
314
+ id
315
+ }
292
316
}
293
317
294
318
fn init_allocation_extra < ' b > (
0 commit comments