44use std:: borrow:: Cow ;
55use std:: cell:: RefCell ;
66use std:: rc:: Rc ;
7+ use std:: collections:: HashMap ;
78
89use rand:: rngs:: StdRng ;
910
10- use rustc_hir:: def_id:: DefId ;
1111use rustc:: mir;
1212use rustc:: ty:: {
1313 self ,
1414 layout:: { LayoutOf , Size } ,
15- Ty , TyCtxt ,
15+ Ty ,
1616} ;
1717use rustc_span:: { source_map:: Span , symbol:: sym} ;
1818use syntax:: attr;
@@ -73,7 +73,11 @@ pub struct MemoryExtra {
7373 pub stacked_borrows : stacked_borrows:: MemoryExtra ,
7474 pub intptrcast : intptrcast:: MemoryExtra ,
7575
76+ /// Mapping extern static names to their canonical allocation.
77+ pub ( crate ) extern_statics : HashMap < & ' static str , AllocId > ,
78+
7679 /// The random number generator used for resolving non-determinism.
80+ /// Needs to be queried by ptr_to_int, hence needs interior mutability.
7781 pub ( crate ) rng : RefCell < StdRng > ,
7882
7983 /// Whether to enforce the validity invariant.
@@ -85,10 +89,30 @@ impl MemoryExtra {
8589 MemoryExtra {
8690 stacked_borrows : Rc :: new ( RefCell :: new ( GlobalState :: new ( tracked_pointer_tag) ) ) ,
8791 intptrcast : Default :: default ( ) ,
92+ extern_statics : HashMap :: default ( ) ,
8893 rng : RefCell :: new ( rng) ,
8994 validate,
9095 }
9196 }
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+ }
92116}
93117
94118/// The machine itself.
@@ -263,32 +287,32 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
263287 Ok ( ( ) )
264288 }
265289
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+ } ;
270303 let attrs = tcx. get_attrs ( def_id) ;
271304 let link_name = match attr:: first_attr_value_str_by_name ( & attrs, sym:: link_name) {
272305 Some ( name) => name. as_str ( ) ,
273306 None => tcx. item_name ( def_id) . as_str ( ) ,
274307 } ;
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+ }
292316 }
293317
294318 fn init_allocation_extra < ' b > (
0 commit comments