[llvm-commits] [compiler-rt] r162278 - in /compiler-rt/trunk/lib/asan: asan_flags.h asan_globals.cc asan_interface.h asan_internal.h asan_report.cc asan_rtl.cc

Kostya Serebryany kcc at google.com
Tue Aug 21 07:10:26 PDT 2012


Author: kcc
Date: Tue Aug 21 09:10:25 2012
New Revision: 162278

URL: http://llvm.org/viewvc/llvm-project?rev=162278&view=rev
Log:
[asan] run-time part of the initialization order checker. Patch by Reid Watson with some bits from kcc. The sub-pass is off by default for now. On simple tests it works fine. 

Modified:
    compiler-rt/trunk/lib/asan/asan_flags.h
    compiler-rt/trunk/lib/asan/asan_globals.cc
    compiler-rt/trunk/lib/asan/asan_interface.h
    compiler-rt/trunk/lib/asan/asan_internal.h
    compiler-rt/trunk/lib/asan/asan_report.cc
    compiler-rt/trunk/lib/asan/asan_rtl.cc

Modified: compiler-rt/trunk/lib/asan/asan_flags.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_flags.h?rev=162278&r1=162277&r2=162278&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_flags.h (original)
+++ compiler-rt/trunk/lib/asan/asan_flags.h Tue Aug 21 09:10:25 2012
@@ -43,6 +43,8 @@
   // on globals, 1 - detect buffer overflow, 2 - print data about registered
   // globals).
   int  report_globals;
+  // If set, attempts to catch initialization order issues.
+  bool check_initialization_order;
   // Max number of stack frames kept for each allocation.
   int  malloc_context_size;
   // If set, uses custom wrappers and replacements for libc string functions

Modified: compiler-rt/trunk/lib/asan/asan_globals.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_globals.cc?rev=162278&r1=162277&r2=162278&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_globals.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_globals.cc Tue Aug 21 09:10:25 2012
@@ -31,8 +31,9 @@
 };
 
 static AsanLock mu_for_globals(LINKER_INITIALIZED);
-static ListOfGlobals *list_of_globals;
 static LowLevelAllocator allocator_for_globals(LINKER_INITIALIZED);
+static ListOfGlobals *list_of_all_globals;
+static ListOfGlobals *list_of_dynamic_init_globals;
 
 void PoisonRedZones(const Global &g)  {
   uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
@@ -63,7 +64,7 @@
   if (!flags()->report_globals) return false;
   ScopedLock lock(&mu_for_globals);
   bool res = false;
-  for (ListOfGlobals *l = list_of_globals; l; l = l->next) {
+  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     const Global &g = *l->g;
     if (flags()->report_globals >= 2)
       Report("Search Global: beg=%p size=%zu name=%s\n",
@@ -78,6 +79,10 @@
 // so we store the globals in a map.
 static void RegisterGlobal(const Global *g) {
   CHECK(asan_inited);
+  if (flags()->report_globals >= 2)
+    Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
+           (void*)g->beg, g->size, g->size_with_redzone, g->name,
+           g->has_dynamic_init);
   CHECK(flags()->report_globals);
   CHECK(AddrIsInMem(g->beg));
   CHECK(AddrIsAlignedByGranularity(g->beg));
@@ -86,11 +91,14 @@
   ListOfGlobals *l =
       (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
   l->g = g;
-  l->next = list_of_globals;
-  list_of_globals = l;
-  if (flags()->report_globals >= 2)
-    Report("Added Global: beg=%p size=%zu name=%s\n",
-           (void*)g->beg, g->size, g->name);
+  l->next = list_of_all_globals;
+  list_of_all_globals = l;
+  if (g->has_dynamic_init) {
+    l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
+    l->g = g;
+    l->next = list_of_dynamic_init_globals;
+    list_of_dynamic_init_globals = l;
+  }
 }
 
 static void UnregisterGlobal(const Global *g) {
@@ -105,6 +113,30 @@
   // implementation. It might not be worth doing anyway.
 }
 
+// Poison all shadow memory for a single global.
+static void PoisonGlobalAndRedzones(const Global *g) {
+  CHECK(asan_inited);
+  CHECK(flags()->check_initialization_order);
+  CHECK(AddrIsInMem(g->beg));
+  CHECK(AddrIsAlignedByGranularity(g->beg));
+  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+  if (flags()->report_globals >= 3)
+    Printf("DynInitPoison  : %s\n", g->name);
+  PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
+}
+
+static void UnpoisonGlobal(const Global *g) {
+  CHECK(asan_inited);
+  CHECK(flags()->check_initialization_order);
+  CHECK(AddrIsInMem(g->beg));
+  CHECK(AddrIsAlignedByGranularity(g->beg));
+  CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
+  if (flags()->report_globals >= 3)
+    Printf("DynInitUnpoison: %s\n", g->name);
+  PoisonShadow(g->beg, g->size_with_redzone, 0);
+  PoisonRedZones(*g);
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
@@ -133,7 +165,7 @@
 }
 
 // Unregister an array of globals.
-// We must do it when a shared objects gets dlclosed.
+// We must do this when a shared objects gets dlclosed.
 void __asan_unregister_globals(__asan_global *globals, uptr n) {
   if (!flags()->report_globals) return;
   ScopedLock lock(&mu_for_globals);
@@ -141,3 +173,36 @@
     UnregisterGlobal(&globals[i]);
   }
 }
+
+// This method runs immediately prior to dynamic initialization in each TU,
+// when all dynamically initialized globals are unpoisoned.  This method
+// poisons all global variables not defined in this TU, so that a dynamic
+// initializer can only touch global variables in the same TU.
+void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
+  if (!flags()->check_initialization_order) return;
+  CHECK(list_of_dynamic_init_globals);
+  ScopedLock lock(&mu_for_globals);
+  bool from_current_tu = false;
+  // The list looks like:
+  // a => ... => b => last_addr => ... => first_addr => c => ...
+  // The globals of the current TU reside between last_addr and first_addr.
+  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
+    if (l->g->beg == last_addr)
+      from_current_tu = true;
+    if (!from_current_tu)
+      PoisonGlobalAndRedzones(l->g);
+    if (l->g->beg == first_addr)
+      from_current_tu = false;
+  }
+  CHECK(!from_current_tu);
+}
+
+// This method runs immediately after dynamic initialization in each TU, when
+// all dynamically initialized globals except for those defined in the current
+// TU are poisoned.  It simply unpoisons all dynamically initialized globals.
+void __asan_after_dynamic_init() {
+  if (!flags()->check_initialization_order) return;
+  ScopedLock lock(&mu_for_globals);
+  for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
+    UnpoisonGlobal(l->g);
+}

Modified: compiler-rt/trunk/lib/asan/asan_interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interface.h?rev=162278&r1=162277&r2=162278&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interface.h (original)
+++ compiler-rt/trunk/lib/asan/asan_interface.h Tue Aug 21 09:10:25 2012
@@ -48,6 +48,14 @@
   void __asan_unregister_globals(__asan_global *globals, uptr n)
       SANITIZER_INTERFACE_ATTRIBUTE;
 
+  // These two functions should be called before and after dynamic initializers
+  // run, respectively.  They should be called with parameters describing all
+  // dynamically initialized globals defined in the calling TU.
+  void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
+      SANITIZER_INTERFACE_ATTRIBUTE;
+  void __asan_after_dynamic_init()
+      SANITIZER_INTERFACE_ATTRIBUTE;
+
   // These two functions are used by the instrumented code in the
   // use-after-return mode. __asan_stack_malloc allocates size bytes of
   // fake stack and __asan_stack_free poisons it. real_stack is a pointer to

Modified: compiler-rt/trunk/lib/asan/asan_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_internal.h?rev=162278&r1=162277&r2=162278&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_internal.h (original)
+++ compiler-rt/trunk/lib/asan/asan_internal.h Tue Aug 21 09:10:25 2012
@@ -171,6 +171,7 @@
 const int kAsanStackRightRedzoneMagic = 0xf3;
 const int kAsanStackPartialRedzoneMagic = 0xf4;
 const int kAsanStackAfterReturnMagic = 0xf5;
+const int kAsanInitializationOrderMagic = 0xf6;
 const int kAsanUserPoisonedMemoryMagic = 0xf7;
 const int kAsanGlobalRedzoneMagic = 0xf9;
 const int kAsanInternalHeapMagic = 0xfe;

Modified: compiler-rt/trunk/lib/asan/asan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.cc?rev=162278&r1=162277&r2=162278&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_report.cc Tue Aug 21 09:10:25 2012
@@ -371,6 +371,9 @@
       case kAsanStackLeftRedzoneMagic:
         bug_descr = "stack-buffer-underflow";
         break;
+      case kAsanInitializationOrderMagic:
+        bug_descr = "initialization-order-fiasco";
+        break;
       case kAsanStackMidRedzoneMagic:
       case kAsanStackRightRedzoneMagic:
       case kAsanStackPartialRedzoneMagic:

Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=162278&r1=162277&r2=162278&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Tue Aug 21 09:10:25 2012
@@ -79,6 +79,7 @@
 
   ParseFlag(str, &f->debug, "debug");
   ParseFlag(str, &f->report_globals, "report_globals");
+  ParseFlag(str, &f->check_initialization_order, "initialization_order");
   ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
   CHECK(f->malloc_context_size <= kMallocContextSize);
 
@@ -116,6 +117,7 @@
   f->redzone = (ASAN_LOW_MEMORY) ? 64 : 128;
   f->debug = false;
   f->report_globals = 1;
+  f->check_initialization_order = true;
   f->malloc_context_size = kMallocContextSize;
   f->replace_str = true;
   f->replace_intrin = true;





More information about the llvm-commits mailing list