[compiler-rt] r213783 - [UBSan] Add the ability to dump call stacks to -fsanitize=vptr

Alexey Samsonov vonosmas at gmail.com
Wed Jul 23 11:44:54 PDT 2014


Author: samsonov
Date: Wed Jul 23 13:44:54 2014
New Revision: 213783

URL: http://llvm.org/viewvc/llvm-project?rev=213783&view=rev
Log:
[UBSan] Add the ability to dump call stacks to -fsanitize=vptr

This change introduces the first UBSan-specific runtime flag: print_stacktrace
(off by default). It can be set in UBSAN_OPTIONS to unwind and print call stacks
in addition to diagnostic messages. For now these stacks are printed only
in vptr checker.

This change is based on http://reviews.llvm.org/D4410 by Byoungyoung Lee!

Added:
    compiler-rt/trunk/lib/ubsan/ubsan_flags.cc
    compiler-rt/trunk/lib/ubsan/ubsan_flags.h
Modified:
    compiler-rt/trunk/lib/ubsan/CMakeLists.txt
    compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
    compiler-rt/trunk/lib/ubsan/ubsan_diag.h
    compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
    compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp

Modified: compiler-rt/trunk/lib/ubsan/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/CMakeLists.txt?rev=213783&r1=213782&r2=213783&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/ubsan/CMakeLists.txt Wed Jul 23 13:44:54 2014
@@ -2,6 +2,7 @@
 
 set(UBSAN_SOURCES
   ubsan_diag.cc
+  ubsan_flags.cc
   ubsan_handlers.cc
   ubsan_value.cc
   )

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=213783&r1=213782&r2=213783&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.cc Wed Jul 23 13:44:54 2014
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ubsan_diag.h"
+#include "ubsan_flags.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -37,9 +38,28 @@ static void InitializeSanitizerCommonAnd
     // Common flags may only be modified via UBSAN_OPTIONS.
     ParseCommonFlagsFromString(cf, GetEnv("UBSAN_OPTIONS"));
   }
+  // Initialize UBSan-specific flags.
+  InitializeFlags();
   initialized = true;
 }
 
+void __ubsan::MaybePrintStackTrace(uptr pc, uptr bp) {
+  // We assume that flags are already parsed: InitializeSanitizerCommonAndFlags
+  // will definitely be called when we print the first diagnostics message.
+  if (!flags()->print_stacktrace)
+    return;
+  // We can only use slow unwind, as we don't have any information about stack
+  // top/bottom.
+  // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
+  // fetch stack top/bottom information if we have it (e.g. if we're running
+  // under ASan).
+  if (StackTrace::WillUseFastUnwind(false))
+    return;
+  StackTrace stack;
+  stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+  stack.Print();
+}
+
 namespace {
 class Decorator : public SanitizerCommonDecorator {
  public:

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.h?rev=213783&r1=213782&r2=213783&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.h Wed Jul 23 13:44:54 2014
@@ -14,6 +14,7 @@
 #define UBSAN_DIAG_H
 
 #include "ubsan_value.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 
 namespace __ubsan {
 
@@ -203,6 +204,13 @@ public:
   Diag &operator<<(const Range &R) { return AddRange(R); }
 };
 
+void MaybePrintStackTrace(uptr pc, uptr bp);
+
+#define MAYBE_PRINT_STACK_TRACE() do { \
+  GET_CALLER_PC_BP_SP; \
+  MaybePrintStackTrace(pc, bp); \
+} while (0)
+
 } // namespace __ubsan
 
 #endif // UBSAN_DIAG_H

Added: compiler-rt/trunk/lib/ubsan/ubsan_flags.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_flags.cc?rev=213783&view=auto
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_flags.cc (added)
+++ compiler-rt/trunk/lib/ubsan/ubsan_flags.cc Wed Jul 23 13:44:54 2014
@@ -0,0 +1,34 @@
+//===-- ubsan_flags.cc ----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __ubsan {
+
+Flags ubsan_flags;
+
+void InitializeFlags() {
+  Flags *f = flags();
+  // Default values.
+  f->print_stacktrace = false;
+
+  const char *options = GetEnv("UBSAN_OPTIONS");
+  if (options) {
+    ParseFlag(options, &f->print_stacktrace, "print_stacktrace",
+              "Include full stacktrace into an error report");
+  }
+}
+
+}  // namespace __ubsan

Added: compiler-rt/trunk/lib/ubsan/ubsan_flags.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_flags.h?rev=213783&view=auto
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_flags.h (added)
+++ compiler-rt/trunk/lib/ubsan/ubsan_flags.h Wed Jul 23 13:44:54 2014
@@ -0,0 +1,29 @@
+//===-- ubsan_flags.h -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Runtime flags for UndefinedBehaviorSanitizer.
+//
+//===----------------------------------------------------------------------===//
+#ifndef UBSAN_FLAGS_H
+#define UBSAN_FLAGS_H
+
+namespace __ubsan {
+
+struct Flags {
+  bool print_stacktrace;
+};
+
+extern Flags ubsan_flags;
+inline Flags *flags() { return &ubsan_flags; }
+
+void InitializeFlags();
+
+}  // namespace __ubsan
+
+#endif  // UBSAN_FLAGS_H

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=213783&r1=213782&r2=213783&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Wed Jul 23 13:44:54 2014
@@ -60,6 +60,7 @@ static void HandleDynamicTypeCacheMiss(
       << MangledName(DTI.getSubobjectTypeName())
       << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1");
 
+  MAYBE_PRINT_STACK_TRACE();
   if (Abort)
     Die();
 }

Modified: compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp?rev=213783&r1=213782&r2=213783&view=diff
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp (original)
+++ compiler-rt/trunk/test/ubsan/TestCases/TypeCheck/vptr.cpp Wed Jul 23 13:44:54 2014
@@ -1,15 +1,15 @@
-// RUN: %clangxx -fsanitize=vptr %s -O3 -o %t
+// RUN: %clangxx -fsanitize=vptr -g %s -O3 -o %t
 // RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
 // RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
 // RUN: %run %t rS && %run %t rV && %run %t oV
-// RUN: %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
-// RUN: %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
-// RUN: %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
-// RUN: %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
-// RUN: %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
-// RUN: %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
-// RUN: %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
-// RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
 
 // FIXME: This test produces linker errors on Darwin.
 // XFAIL: darwin
@@ -77,11 +77,12 @@ int main(int, char **argv) {
     break;
 
   case 'm':
-    // CHECK-MEMBER: vptr.cpp:[[@LINE+5]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
     // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
     // CHECK-MEMBER-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
+    // CHECK-MEMBER-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE+1]]
     return p->b;
 
     // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
@@ -89,29 +90,33 @@ int main(int, char **argv) {
     // CHECK-NULL-MEMBER-NEXT: {{^  ?.. .. .. ..  ?00 00 00 00  ?00 00 00 00  ?}}
     // CHECK-NULL-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-NULL-MEMBER-NEXT: {{^              invalid vptr}}
+    // CHECK-NULL-MEMBER-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE-7]]
 
   case 'f':
-    // CHECK-MEMFUN: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
     // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
     // CHECK-MEMFUN-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
+    // TODO: Add check for stacktrace here.
     return p->g();
 
   case 'o':
-    // CHECK-OFFSET: vptr.cpp:[[@LINE+5]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
+    // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
     // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
     // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
     // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} 'T' base class of [[DYN_TYPE]]
+    // CHECK-OFFSET-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE+1]]
     return reinterpret_cast<U*>(p)->v() - 2;
 
   case 'c':
-    // CHECK-DOWNCAST: vptr.cpp:[[@LINE+5]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+    // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
     // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
     // CHECK-DOWNCAST-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
     // CHECK-DOWNCAST-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
     // CHECK-DOWNCAST-NEXT: {{^              vptr for}} [[DYN_TYPE]]
+    // CHECK-DOWNCAST-NEXT: #0 {{.*}} in main {{.*}}vptr.cpp:[[@LINE+1]]
     static_cast<T*>(reinterpret_cast<S*>(p));
     return 0;
   }





More information about the llvm-commits mailing list