Allow __asan_{before,after}_dynamic_init without registered globals

Jakub Jelinek via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 2 09:06:43 PDT 2016


Hi!

When optimizing, GCC optimizes away aggressively unused static globals.
The __asan_before_dynamic_init/__asan_after_dynamic_init calls are placed
in static constructor earlier while the registration of the globals is done
later in the compilation process.  If all the globals with
dynamic initialization are optimized away from some particular TU in between
those two, libasan can fail on an assertion that dynamic_init_globals is
empty.

While I'm going to commit a GCC change which will remove the
__asan_before_dynamic_init/__asan_after_dynamic_init in many cases when this
happens (basically if the optimizers can prove there are no memory
references in between the two calls), there are still testcases where such
pair of calls is left, e.g. for
struct S { S () { asm volatile ("" : : : "memory"); } };
static S c;

int
main ()
{
  return 0;
}
with -O2 -fsanitize=address and ASAN_OPTIONS=check_initialization_order=true
this still fails the assertion.  Trying to avoid this problem on the
compiler side would decrease code quality I'm afraid, whether it is making
sure for -fsanitize=address we keep around at least one dynamically
initialized global if the
__asan_before_dynamic_init/__asan_after_dynamic_init pair has been emitted,
or adding some artificial global which would be used as the condition for
those calls etc.
So, can the assertion be instead just removed, this really shouldn't slow
down the calls measurably (for __asan_before_dynamic_init it is even
cheaper) and the assertion doesn't check something worthwhile anyway (it is
sufficient if there is a single dynamically initialized global in any other
TU to make it happy).

Details in http://gcc.gnu.org/PR77396

--- compiler-rt/lib/asan/asan_globals.cc	(revision 280486)
+++ compiler-rt/lib/asan/asan_globals.cc	(working copy)
@@ -368,10 +368,10 @@ void __asan_unregister_globals(__asan_gl
 // initializer can only touch global variables in the same TU.
 void __asan_before_dynamic_init(const char *module_name) {
   if (!flags()->check_initialization_order ||
-      !CanPoisonMemory())
+      !CanPoisonMemory() ||
+      !dynamic_init_globals)
     return;
   bool strict_init_order = flags()->strict_init_order;
-  CHECK(dynamic_init_globals);
   CHECK(module_name);
   CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);
@@ -394,7 +394,8 @@ void __asan_before_dynamic_init(const ch
 // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
 void __asan_after_dynamic_init() {
   if (!flags()->check_initialization_order ||
-      !CanPoisonMemory())
+      !CanPoisonMemory() ||
+      !dynamic_init_globals)
     return;
   CHECK(asan_inited);
   BlockingMutexLock lock(&mu_for_globals);

	Jakub


More information about the llvm-commits mailing list