Index: lib/ubsan/ubsan_diag.h =================================================================== --- lib/ubsan/ubsan_diag.h +++ lib/ubsan/ubsan_diag.h @@ -14,9 +14,22 @@ #define UBSAN_DIAG_H #include "ubsan_value.h" +#include "sanitizer_common/sanitizer_stacktrace.h" namespace __ubsan { +#define MAX_PRINT_STACK_DEPTH 50 + +void InitializeSanitizerCommon(); + +// \brief Print the current stack traces while skipping the caller's frame. +ALWAYS_INLINE void PrintCurrentStack() { + StackTrace stack; + stack.Unwind(MAX_PRINT_STACK_DEPTH, GET_CALLER_PC(), GET_CURRENT_FRAME(), + 0, 0, 0, false); + stack.Print(); +} + /// \brief A location within a loaded module in the program. These are used when /// the location can't be resolved to a SourceLocation. class ModuleLocation { Index: lib/ubsan/ubsan_diag.cc =================================================================== --- lib/ubsan/ubsan_diag.cc +++ lib/ubsan/ubsan_diag.cc @@ -22,7 +22,7 @@ using namespace __ubsan; -static void InitializeSanitizerCommon() { +void __ubsan::InitializeSanitizerCommon() { static StaticSpinMutex init_mu; SpinMutexLock l(&init_mu); static bool initialized; @@ -34,6 +34,11 @@ CommonFlags *cf = common_flags(); SetCommonFlagsDefaults(cf); cf->print_summary = false; + + // Initialize symbolizer with an empty string to avoid aggressive online + // symbolizations. + if (GetEnv("UBSAN_NO_SYMBOLIZE")) + Symbolizer::Init(""); } initialized = true; } Index: lib/ubsan/ubsan_handlers_cxx.cc =================================================================== --- lib/ubsan/ubsan_handlers_cxx.cc +++ lib/ubsan/ubsan_handlers_cxx.cc @@ -29,6 +29,14 @@ static void HandleDynamicTypeCacheMiss( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash, bool Abort) { + // The initialization routine has to be invoked in the early process runinng + // phase (before PrepareForSandboxing() get invoked), but UBsan does not + // interpose any process startup functions (e.g., .preinit_array for Linux). + // + // FIXME: This paranoid try may significantly slowdown the execution due to + // the syncronization in InitializeSanitizerCommon(). + InitializeSanitizerCommon(); + if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash)) // Just a cache miss. The type matches after all. return; @@ -60,6 +68,8 @@ << MangledName(DTI.getSubobjectTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1"); + PrintCurrentStack(); + if (Abort) Die(); } Index: test/ubsan/TestCases/TypeCheck/vptr.cpp =================================================================== --- test/ubsan/TestCases/TypeCheck/vptr.cpp +++ test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -77,11 +77,13 @@ 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+7]]: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 [[PTR:0x[0-9a-f]*]] in + // CHECK-MEMBER-NEXT: #1 [[PTR:0x[0-9a-f]*]] in 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 +91,37 @@ // 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 [[PTR:0x[0-9a-f]*]] in + // CHECK-NULL-MEMBER-NEXT: #1 [[PTR:0x[0-9a-f]*]] in 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+7]]: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]] + // CHECK-MEMFUN-NEXT: #0 [[PTR:0x[0-9a-f]*]] in + // CHECK-MEMFUN-NEXT: #1 [[PTR:0x[0-9a-f]*]] in 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+7]]: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 [[PTR:0x[0-9a-f]*]] in + // CHECK-OFFSET-NEXT: #1 [[PTR:0x[0-9a-f]*]] in return reinterpret_cast(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+7]]: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 [[PTR:0x[0-9a-f]*]] in + // CHECK-DOWNCAST-NEXT: #1 [[PTR:0x[0-9a-f]*]] in static_cast(reinterpret_cast(p)); return 0; }