@@ -47,8 +47,6 @@ struct DynInitGlobal {
47
47
bool initialized = false ;
48
48
DynInitGlobal *next = nullptr ;
49
49
};
50
- typedef IntrusiveList<DynInitGlobal> DynInitGlobals;
51
- static DynInitGlobals dynamic_init_globals SANITIZER_GUARDED_BY (mu_for_globals);
52
50
53
51
// We want to remember where a certain range of globals was registered.
54
52
struct GlobalRegistrationSite {
@@ -72,6 +70,25 @@ static ListOfGlobals &GlobalsByIndicator(uptr odr_indicator)
72
70
return (*globals_by_indicator)[odr_indicator];
73
71
}
74
72
73
+ static const char *current_dynamic_init_module_name
74
+ SANITIZER_GUARDED_BY (mu_for_globals) = nullptr ;
75
+
76
+ using DynInitGlobalsByModule =
77
+ DenseMap<const char *, IntrusiveList<DynInitGlobal>>;
78
+
79
+ // TODO: Add a NoDestroy helper, this patter is very common in sanitizers.
80
+ static DynInitGlobalsByModule &DynInitGlobals ()
81
+ SANITIZER_REQUIRES(mu_for_globals) {
82
+ static DynInitGlobalsByModule *globals_by_module = nullptr ;
83
+ if (!globals_by_module) {
84
+ alignas (alignof (DynInitGlobalsByModule)) static char
85
+ placeholder[sizeof (DynInitGlobalsByModule)];
86
+ globals_by_module = new (placeholder) DynInitGlobalsByModule ();
87
+ }
88
+
89
+ return *globals_by_module;
90
+ }
91
+
75
92
ALWAYS_INLINE void PoisonShadowForGlobal (const Global *g, u8 value) {
76
93
FastPoisonShadow (g->beg , g->size_with_redzone , value);
77
94
}
@@ -94,6 +111,31 @@ static void AddGlobalToList(ListOfGlobals &list, const Global *g) {
94
111
list.push_front (new (GetGlobalLowLevelAllocator ()) GlobalListNode{g});
95
112
}
96
113
114
+ static void UnpoisonDynamicGlobals (IntrusiveList<DynInitGlobal> &dyn_globals,
115
+ bool mark_initialized) {
116
+ for (auto &dyn_g : dyn_globals) {
117
+ const Global *g = &dyn_g.g ;
118
+ if (dyn_g.initialized )
119
+ continue ;
120
+ // Unpoison the whole global.
121
+ PoisonShadowForGlobal (g, 0 );
122
+ // Poison redzones back.
123
+ PoisonRedZones (*g);
124
+ if (mark_initialized)
125
+ dyn_g.initialized = true ;
126
+ }
127
+ }
128
+
129
+ static void PoisonDynamicGlobals (
130
+ const IntrusiveList<DynInitGlobal> &dyn_globals) {
131
+ for (auto &dyn_g : dyn_globals) {
132
+ const Global *g = &dyn_g.g ;
133
+ if (dyn_g.initialized )
134
+ continue ;
135
+ PoisonShadowForGlobal (g, kAsanInitializationOrderMagic );
136
+ }
137
+ }
138
+
97
139
static bool IsAddressNearGlobal (uptr addr, const __asan_global &g) {
98
140
if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal ) return false ;
99
141
if (addr >= g.beg + g.size_with_redzone ) return false ;
@@ -257,8 +299,8 @@ static void RegisterGlobal(const Global *g) SANITIZER_REQUIRES(mu_for_globals) {
257
299
AddGlobalToList (list_of_all_globals, g);
258
300
259
301
if (g->has_dynamic_init ) {
260
- dynamic_init_globals .push_back (new ( GetGlobalLowLevelAllocator ())
261
- DynInitGlobal{*g, false });
302
+ DynInitGlobals ()[g-> module_name ] .push_back (
303
+ new ( GetGlobalLowLevelAllocator ()) DynInitGlobal{*g, false });
262
304
}
263
305
}
264
306
@@ -289,13 +331,10 @@ void StopInitOrderChecking() {
289
331
return ;
290
332
Lock lock (&mu_for_globals);
291
333
flags ()->check_initialization_order = false ;
292
- for (const DynInitGlobal &dyn_g : dynamic_init_globals) {
293
- const Global *g = &dyn_g.g ;
294
- // Unpoison the whole global.
295
- PoisonShadowForGlobal (g, 0 );
296
- // Poison redzones back.
297
- PoisonRedZones (*g);
298
- }
334
+ DynInitGlobals ().forEach ([&](auto &kv) {
335
+ UnpoisonDynamicGlobals (kv.second , /* mark_initialized=*/ false );
336
+ return true ;
337
+ });
299
338
}
300
339
301
340
static bool IsASCII (unsigned char c) { return /* 0x00 <= c &&*/ c <= 0x7F ; }
@@ -456,17 +495,29 @@ void __asan_before_dynamic_init(const char *module_name) {
456
495
CHECK (module_name);
457
496
CHECK (AsanInited ());
458
497
Lock lock (&mu_for_globals);
498
+ if (current_dynamic_init_module_name == module_name)
499
+ return ;
459
500
if (flags ()->report_globals >= 3 )
460
501
Printf (" DynInitPoison module: %s\n " , module_name);
461
- for (DynInitGlobal &dyn_g : dynamic_init_globals) {
462
- const Global *g = &dyn_g.g ;
463
- if (dyn_g.initialized )
464
- continue ;
465
- if (g->module_name != module_name)
466
- PoisonShadowForGlobal (g, kAsanInitializationOrderMagic );
467
- else if (!strict_init_order)
468
- dyn_g.initialized = true ;
502
+
503
+ if (current_dynamic_init_module_name == nullptr ) {
504
+ // First call, poison all globals from other modules.
505
+ DynInitGlobals ().forEach ([&](auto &kv) {
506
+ if (kv.first != module_name) {
507
+ PoisonDynamicGlobals (kv.second );
508
+ } else {
509
+ UnpoisonDynamicGlobals (kv.second ,
510
+ /* mark_initialized=*/ !strict_init_order);
511
+ }
512
+ return true ;
513
+ });
514
+ } else {
515
+ // Module changed.
516
+ PoisonDynamicGlobals (DynInitGlobals ()[current_dynamic_init_module_name]);
517
+ UnpoisonDynamicGlobals (DynInitGlobals ()[module_name],
518
+ /* mark_initialized=*/ !strict_init_order);
469
519
}
520
+ current_dynamic_init_module_name = module_name;
470
521
}
471
522
472
523
// This method runs immediately after dynamic initialization in each TU, when
@@ -477,15 +528,16 @@ void __asan_after_dynamic_init() {
477
528
return ;
478
529
CHECK (AsanInited ());
479
530
Lock lock (&mu_for_globals);
531
+ if (!current_dynamic_init_module_name)
532
+ return ;
533
+
480
534
if (flags ()->report_globals >= 3 )
481
535
Printf (" DynInitUnpoison\n " );
482
- for (const DynInitGlobal &dyn_g : dynamic_init_globals) {
483
- const Global *g = &dyn_g.g ;
484
- if (!dyn_g.initialized ) {
485
- // Unpoison the whole global.
486
- PoisonShadowForGlobal (g, 0 );
487
- // Poison redzones back.
488
- PoisonRedZones (*g);
489
- }
490
- }
536
+
537
+ DynInitGlobals ().forEach ([&](auto &kv) {
538
+ UnpoisonDynamicGlobals (kv.second , /* mark_initialized=*/ false );
539
+ return true ;
540
+ });
541
+
542
+ current_dynamic_init_module_name = nullptr ;
491
543
}
0 commit comments