[compiler-rt] r212188 - [ASan] Print exact source location of global variables in error reports.

Alexey Samsonov vonosmas at gmail.com
Wed Jul 2 09:54:42 PDT 2014


Author: samsonov
Date: Wed Jul  2 11:54:41 2014
New Revision: 212188

URL: http://llvm.org/viewvc/llvm-project?rev=212188&view=rev
Log:
[ASan] Print exact source location of global variables in error reports.

See https://code.google.com/p/address-sanitizer/issues/detail?id=299 for the
original feature request.

Introduce llvm.asan.globals metadata, which Clang (or any other frontend)
may use to report extra information about global variables to ASan
instrumentation pass in the backend. This metadata replaces
llvm.asan.dynamically_initialized_globals that was used to detect init-order
bugs. llvm.asan.globals contains the following data for each global:
  1) source location (file/line/column info);
  2) whether it is dynamically initialized;
  3) whether it is blacklisted (shouldn't be instrumented).

Source location data is then emitted in the binary and can be picked up
by ASan runtime in case it needs to print error report involving some global.
For example:

  0x... is located 4 bytes to the right of global variable 'C::array' defined in '/path/to/file:17:8' (0x...) of size 40

These source locations are printed even if the binary doesn't have any
debug info.

This is an ABI-breaking change. ASan initialization is renamed to
__asan_init_v4(). Pre-built libraries compiled with older Clang will not work
with the fresh runtime.

Added:
    compiler-rt/trunk/test/asan/TestCases/global-location.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_dll_thunk.cc
    compiler-rt/trunk/lib/asan/asan_interface_internal.h
    compiler-rt/trunk/lib/asan/asan_report.cc

Modified: compiler-rt/trunk/lib/asan/asan_dll_thunk.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_dll_thunk.cc?rev=212188&r1=212187&r2=212188&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_dll_thunk.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_dll_thunk.cc Wed Jul  2 11:54:41 2014
@@ -203,13 +203,13 @@ extern "C" {
 
   // Manually wrap __asan_init as we need to initialize
   // __asan_option_detect_stack_use_after_return afterwards.
-  void __asan_init_v3() {
+  void __asan_init_v4() {
     typedef void (*fntype)();
     static fntype fn = 0;
-    // __asan_init_v3 is expected to be called by only one thread.
+    // __asan_init_v4 is expected to be called by only one thread.
     if (fn) return;
 
-    fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
+    fn = (fntype)getRealProcAddressOrDie("__asan_init_v4");
     fn();
     __asan_option_detect_stack_use_after_return =
         (__asan_should_detect_stack_use_after_return() != 0);
@@ -339,7 +339,7 @@ void InterceptHooks() {
 // In DLLs, the callbacks are expected to return 0,
 // otherwise CRT initialization fails.
 static int call_asan_init() {
-  __asan_init_v3();
+  __asan_init_v4();
   return 0;
 }
 #pragma section(".CRT$XIB", long, read)  // NOLINT

Modified: compiler-rt/trunk/lib/asan/asan_interface_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interface_internal.h?rev=212188&r1=212187&r2=212188&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interface_internal.h (original)
+++ compiler-rt/trunk/lib/asan/asan_interface_internal.h Wed Jul  2 11:54:41 2014
@@ -30,8 +30,17 @@ extern "C" {
   // v2=>v3: stack frame description (created by the compiler)
   //         contains the function PC as the 3-rd field (see
   //         DescribeAddressIfStack).
-  SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3();
-  #define __asan_init __asan_init_v3
+  // v3=>v4: added '__asan_global_source_location' to __asan_global.
+  SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v4();
+  #define __asan_init __asan_init_v4
+
+  // This structure is used to describe the source location of a place where
+  // global was defined.
+  struct __asan_global_source_location {
+    const char *filename;
+    int line_no;
+    int column_no;
+  };
 
   // This structure describes an instrumented global variable.
   struct __asan_global {
@@ -42,6 +51,8 @@ extern "C" {
     const char *module_name; // Module name as a C string. This pointer is a
                              // unique identifier of a module.
     uptr has_dynamic_init;   // Non-zero if the global has dynamic initializer.
+    __asan_global_source_location *location;  // Source location of a global,
+                                              // or NULL if it is unknown.
   };
 
   // These two functions should be called by the instrumented code.

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=212188&r1=212187&r2=212188&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_report.cc Wed Jul  2 11:54:41 2014
@@ -212,6 +212,26 @@ static void PrintGlobalNameIfASCII(Inter
               (char *)g.beg);
 }
 
+static const char *GlobalFilename(const __asan_global &g) {
+  const char *res = g.module_name;
+  // Prefer the filename from source location, if is available.
+  if (g.location)
+    res = g.location->filename;
+  CHECK(res);
+  return res;
+}
+
+static void PrintGlobalLocation(InternalScopedString *str,
+                                const __asan_global &g) {
+  str->append("%s", GlobalFilename(g));
+  if (!g.location)
+    return;
+  if (g.location->line_no)
+    str->append(":%d", g.location->line_no);
+  if (g.location->column_no)
+    str->append(":%d", g.location->column_no);
+}
+
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
                                      const __asan_global &g) {
   static const uptr kMinimalDistanceFromAnotherGlobal = 64;
@@ -232,8 +252,10 @@ bool DescribeAddressRelativeToGlobal(upt
     // Can it happen?
     str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
   }
-  str.append(" of global variable '%s' from '%s' (0x%zx) of size %zu\n",
-             MaybeDemangleGlobalName(g.name), g.module_name, g.beg, g.size);
+  str.append(" of global variable '%s' defined in '",
+             MaybeDemangleGlobalName(g.name));
+  PrintGlobalLocation(&str, g);
+  str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
   str.append("%s", d.EndLocation());
   PrintGlobalNameIfASCII(&str, g);
   Printf("%s", str.data());
@@ -742,8 +764,11 @@ void ReportODRViolation(const __asan_glo
   Printf("%s", d.Warning());
   Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
   Printf("%s", d.EndWarning());
-  Printf("  [1] size=%zd %s %s\n", g1->size, g1->name, g1->module_name);
-  Printf("  [2] size=%zd %s %s\n", g2->size, g2->name, g2->module_name);
+  InternalScopedString g1_loc(256), g2_loc(256);
+  PrintGlobalLocation(&g1_loc, *g1);
+  PrintGlobalLocation(&g2_loc, *g2);
+  Printf("  [1] size=%zd %s %s\n", g1->size, g1->name, g1_loc.data());
+  Printf("  [2] size=%zd %s %s\n", g2->size, g2->name, g2_loc.data());
   if (stack_id1 && stack_id2) {
     Printf("These globals were registered at these points:\n");
     Printf("  [1]:\n");
@@ -756,7 +781,7 @@ void ReportODRViolation(const __asan_glo
   }
   Report("HINT: if you don't care about these warnings you may set "
          "ASAN_OPTIONS=detect_odr_violation=0\n");
-  ReportErrorSummary("odr-violation", g1->module_name, 0, g1->name);
+  ReportErrorSummary("odr-violation", g1_loc.data(), 0, g1->name);
 }
 
 // ----------------------- CheckForInvalidPointerPair ----------- {{{1

Added: compiler-rt/trunk/test/asan/TestCases/global-location.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/global-location.cc?rev=212188&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/global-location.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/global-location.cc Wed Jul  2 11:54:41 2014
@@ -0,0 +1,38 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t g 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=GLOB
+// RUN: not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CLASS_STATIC
+// RUN: not %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=FUNC_STATIC
+// RUN: not %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=LITERAL
+
+// CHECK: AddressSanitizer: global-buffer-overflow
+
+#include <string.h>
+
+struct C {
+  static int array[10];
+};
+
+int global[10];
+// GLOB: 0x{{.*}} is located 4 bytes to the right of global variable 'global' defined in '{{.*}}global-location.cc:[[@LINE-1]]:5' {{.*}} of size 40
+int C::array[10];
+// CLASS_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'C::array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:8' {{.*}} of size 40
+
+int main(int argc, char **argv) {
+  int one = argc - 1;
+  switch (argv[1][0]) {
+  case 'g': return global[one * 11];
+  case 'c': return C::array[one * 11];
+  case 'f':
+    static int array[10];
+    // FUNC_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'main::array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:16' {{.*}} of size 40
+    memset(array, 0, 10);
+    return array[one * 11];
+  case 'l':
+    const char *str = "0123456789";
+    // LITERAL: 0x{{.*}} is located 0 bytes to the right of global variable {{.*}} defined in '{{.*}}global-location.cc:[[@LINE-1]]:23' {{.*}} of size 11
+    return str[one * 11];
+  }
+  return 0;
+}
+
+// CHECK: SUMMARY: AddressSanitizer: global-buffer-overflow





More information about the llvm-commits mailing list