Index: lib/asan/asan_debugging.cc =================================================================== --- lib/asan/asan_debugging.cc +++ lib/asan/asan_debugging.cc @@ -28,19 +28,19 @@ descr->region_size = 0; descr->region_kind = "stack"; - uptr offset = 0; - uptr frame_pc = 0; - const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc); + AsanThread::StackFrameAccess access; + if (!t->GetStackFrameAccessByAddr(addr, &access)) + return; InternalMmapVector vars(16); - if (!ParseFrameDescription(frame_descr, &vars)) { + if (!ParseFrameDescription(access.frame_descr, &vars)) { return; } for (uptr i = 0; i < vars.size(); i++) { - if (offset <= vars[i].beg + vars[i].size) { + if (access.offset <= vars[i].beg + vars[i].size) { internal_strncat(descr->name, vars[i].name_pos, Min(descr->name_size, vars[i].name_len)); - descr->region_address = addr - (offset - vars[i].beg); + descr->region_address = addr - (access.offset - vars[i].beg); descr->region_size = vars[i].size; return; } Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -381,9 +381,14 @@ bool ParseFrameDescription(const char *frame_descr, InternalMmapVector *vars) { + CHECK(frame_descr); char *p; + // This string is created by the compiler and has the following form: + // "n alloc_1 alloc_2 ... alloc_n" + // where alloc_i looks like "offset size len ObjectName". uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); - CHECK_GT(n_objects, 0); + if (n_objects == 0) + return false; for (uptr i = 0; i < n_objects; i++) { uptr beg = (uptr)internal_simple_strtoll(p, &p, 10); @@ -404,31 +409,21 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { AsanThread *t = FindThreadByStackAddress(addr); if (!t) return false; - const uptr kBufSize = 4095; - char buf[kBufSize]; - uptr offset = 0; - uptr frame_pc = 0; - char tname[128]; - const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc); -#ifdef __powerpc64__ - // On PowerPC64, the address of a function actually points to a - // three-doubleword data structure with the first field containing - // the address of the function's code. - frame_pc = *reinterpret_cast(frame_pc); -#endif - - // This string is created by the compiler and has the following form: - // "n alloc_1 alloc_2 ... alloc_n" - // where alloc_i looks like "offset size len ObjectName ". - CHECK(frame_descr); Decorator d; + char tname[128]; Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread T%d%s " - "at offset %zu in frame\n", - addr, t->tid(), - ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)), - offset); + Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(), + ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname))); + + // Try to fetch precise stack frame for this access. + AsanThread::StackFrameAccess access; + if (!t->GetStackFrameAccessByAddr(addr, &access)) { + Printf("%s\n", d.EndLocation()); + return true; + } + Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation()); + // Now we print the frame where the alloca has happened. // We print this frame as a stack trace with one element. // The symbolizer may print more than one frame if inlining was involved. @@ -437,15 +432,21 @@ // especially given that the alloca may be from entirely different place // (e.g. use-after-scope, or different thread's stack). StackTrace alloca_stack; - alloca_stack.trace[0] = frame_pc + 16; +#ifdef __powerpc64__ + // On PowerPC64, the address of a function actually points to a + // three-doubleword data structure with the first field containing + // the address of the function's code. + access.frame_pc = *reinterpret_cast(access.frame_pc); +#endif + alloca_stack.trace[0] = access.frame_pc + 16; alloca_stack.size = 1; Printf("%s", d.EndLocation()); alloca_stack.Print(); InternalMmapVector vars(16); - if (!ParseFrameDescription(frame_descr, &vars)) { + if (!ParseFrameDescription(access.frame_descr, &vars)) { Printf("AddressSanitizer can't parse the stack frame " - "descriptor: |%s|\n", frame_descr); + "descriptor: |%s|\n", access.frame_descr); // 'addr' is a stack address, so return true even if we can't parse frame return true; } @@ -454,15 +455,16 @@ Printf(" This frame has %zu object(s):\n", n_objects); // Report all objects in this frame. + const uptr kBufSize = 4095; + char buf[kBufSize]; for (uptr i = 0; i < n_objects; i++) { buf[0] = 0; internal_strncat(buf, vars[i].name_pos, static_cast(Min(kBufSize, vars[i].name_len))); uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); - PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size, - offset, access_size, - prev_var_end, next_var_beg); + PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size, access.offset, + access_size, prev_var_end, next_var_beg); } Printf("HINT: this may be a false positive if your program uses " "some custom stack unwind mechanism or swapcontext\n"); Index: lib/asan/asan_thread.h =================================================================== --- lib/asan/asan_thread.h +++ lib/asan/asan_thread.h @@ -71,7 +71,12 @@ AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } - const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc); + struct StackFrameAccess { + uptr offset; + uptr frame_pc; + const char *frame_descr; + }; + bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access); bool AddrIsInStack(uptr addr) { return addr >= stack_bottom_ && addr < stack_top_; Index: lib/asan/asan_thread.cc =================================================================== --- lib/asan/asan_thread.cc +++ lib/asan/asan_thread.cc @@ -198,17 +198,18 @@ PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); } -const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset, - uptr *frame_pc) { +bool AsanThread::GetStackFrameAccessByAddr(uptr addr, + StackFrameAccess *access) { uptr bottom = 0; if (AddrIsInStack(addr)) { bottom = stack_bottom(); } else if (has_fake_stack()) { bottom = fake_stack()->AddrIsInFakeStack(addr); CHECK(bottom); - *offset = addr - bottom; - *frame_pc = ((uptr*)bottom)[2]; - return (const char *)((uptr*)bottom)[1]; + access->offset = addr - bottom; + access->frame_pc = ((uptr*)bottom)[2]; + access->frame_descr = (const char *)((uptr*)bottom)[1]; + return true; } uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr. u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr); @@ -225,15 +226,15 @@ } if (shadow_ptr < shadow_bottom) { - *offset = 0; - return "UNKNOWN"; + return false; } uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1)); CHECK(ptr[0] == kCurrentStackFrameMagic); - *offset = addr - (uptr)ptr; - *frame_pc = ptr[2]; - return (const char*)ptr[1]; + access->offset = addr - (uptr)ptr; + access->frame_pc = ptr[2]; + access->frame_descr = (const char*)ptr[1]; + return true; } static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, Index: lib/sanitizer_common/scripts/sancov_symbolize.sh =================================================================== --- /dev/null +++ lib/sanitizer_common/scripts/sancov_symbolize.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Usage: sancov_symbolize.sh + +SANCOV_FILE=$1 +EXE_FILE=$2 +OUTPUT_FILE=$3 + +ROOT=$(dirname $0) +${ROOT}/sancov.py print ${SANCOV_FILE} 2>/dev/null | \ + llvm-symbolizer --obj=${EXE_FILE} | \ + sed -e "s/\/proc\/self\/cwd\///" | \ + sed -e "s/^\.\///" > ${OUTPUT_FILE} Index: test/asan/TestCases/Linux/init-order-templ.cc =================================================================== --- /dev/null +++ test/asan/TestCases/Linux/init-order-templ.cc @@ -0,0 +1,26 @@ +// RUN: %clangxx_asan -O0 %s -DSOURCE1 -c -o %t-1.o +// RUN: %clangxx_asan -O0 %s -DSOURCE2 -c -o %t-2.o +// RUN: %clangxx_asan %t-1.o %t-2.o -o %t +// RUN: ASAN_OPTIONS=strict_init_order=true not %run %t 2>&1 | FileCheck %s + +// For now, we can't detect such bugs as globals from template instantiantions +// are linkonce_odr, and we ignore such globals in ASan instrumentation. +// XFAIL: * + +#ifdef SOURCE1 +int foo(); +template struct S1 { static int x; }; +template int S1::x = foo(); +// CHECK: AddressSanitizer: initialization-order-fiasco + +int main(int argc, char *argv[]) { + return S1<0>::x + argc - 1; +} +#endif + +#ifdef SOURCE2 +int bar() { return 0; } +template struct S2 { static int x; }; +template int S2::x = bar(); +int foo() { return S2<0>::x; } +#endif Index: test/ubsan/TestCases/TypeCheck/vptr-shared.cpp.zzz =================================================================== --- /dev/null +++ test/ubsan/TestCases/TypeCheck/vptr-shared.cpp.zzz @@ -0,0 +1,29 @@ +// RUN: %clangxx -fsanitize=vptr -fPIC -DBUILD_SHARED -shared %s -o %t.so +// RUN: %clangxx -fsanitize=vptr %s %t.so -o %t +// RUN: not %t 2>&1 | FileCheck %s + +#ifdef BUILD_SHARED +struct S { + S() : a(0) {} + int a; + virtual int v() { return 0; } +}; + +struct T : S { + T() : b(0) {} + int b; + int v() { return 1; } +}; + +int get_value() { + T *ptr = reinterpret_cast(new S); + return ptr->b; // BUG + // CHECK: vptr-shared.cpp:[[@LINE-1]]:15: runtime error: member access within address 0x{{.*}} which does not point to an object of type 'T' +} +#else +int get_value(); + +int main(int argc, char *argv[]) { + return get_value(); +} +#endif Index: zdesc.allocator =================================================================== --- /dev/null +++ zdesc.allocator @@ -0,0 +1,2 @@ +[Sanitizer] Kill deprecated allocator interfaces in ASan, MSan and TSan in favor of +a unified interface in . Index: zdesc.asan =================================================================== --- /dev/null +++ zdesc.asan @@ -0,0 +1,3 @@ +[ASan] Improve ODR-violation error reports. + +Demangle names of involved globals. Print a more consistent summary line. Index: zdesc.builtins =================================================================== --- /dev/null +++ zdesc.builtins @@ -0,0 +1,7 @@ +Unify the name of compiler-rt builtins library on Linux. + +Call it "libclang_rt.builtins-.a" to be consistent +with sanitizers/profile libraries naming. Modify Makefile +and CMake build systems and Clang driver accordingly. + +Fixes PR19822. Index: zdesc.cmake =================================================================== --- /dev/null +++ zdesc.cmake @@ -0,0 +1,3 @@ +Fix latent bug in try_compile macro and use CMAKE_EXE_LINKER_FLAGS +when testing for supported architectures, as suggested by Andy Gibbs. + Index: zdesc.d4692 =================================================================== --- /dev/null +++ zdesc.d4692 @@ -0,0 +1,5 @@ +Fix fast stack unwind on ARM to support code generated with GCC. + +http://reviews.llvm.org/D4692 + +Patch by Maxim Ostapenko! Index: zdesc.d4703 =================================================================== --- /dev/null +++ zdesc.d4703 @@ -0,0 +1,13 @@ +[ASan] Add new options for asan_symbolize.py script. + +The patch adds new features in asan-symbolizer script which are helpful for using ASan on embedded systems: + +1) add cross-compile prefix for binutils +2) define path to sysroot with sanitized binaries + +Features are enabled by command line options. +The patch also extends command line interface with help option. + +Reviewed in http://reviews.llvm.org/D4703. + +Patch by Maria Guseva! Index: zdesc.ext_libcxx =================================================================== --- /dev/null +++ zdesc.ext_libcxx @@ -0,0 +1,10 @@ +[TSan] Build TSan-instrumented version of libcxx and use it in lit tests. + +TSan can produce false positives in code that uses C++11 threading, +as it doesn't see synchronization inside standard library. See +http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-February/035408.html +for an example of such case. + +We may build custom TSan-instrumented version libcxx to fight with that. +This change adds build rules for libcxx_tsan and integrates it into +testing infrastructure. Index: zdesc.lsan =================================================================== --- /dev/null +++ zdesc.lsan @@ -0,0 +1,7 @@ +[LSan] Parse common flags from LSAN_OPTIONS even if LSan is combined with +another sanitizer. + +A user may run both LSan and LSan+ASan. It is weird to pass path to leak +suppression file (or other common sanitizer flags, like "verbosity") in +"LSAN_OPTIONS" in the first case and in "ASAN_OPTIONS" in the second case. + Index: zdesc.msan =================================================================== --- /dev/null +++ zdesc.msan @@ -0,0 +1,2 @@ +[MSan] Fixup r212082: enable tests for _mm_ intrinsics if and only if the +unit test source file is compiled with Clang. Index: zdesc.san =================================================================== --- /dev/null +++ zdesc.san @@ -0,0 +1,6 @@ +[Sanitizer] Get rid of Symbolizer::Get() and Symbolizer::GetOrNull(). + +We may as well just use Symbolizer::GetOrInit() in all the cases. +Don't call Symbolizer::Get() early in tools initialization: these days +it doesn't do any important setup work, and we may as well create the +symbolizer the first time it's actually needed. Index: zdesc.sanitizer =================================================================== --- /dev/null +++ zdesc.sanitizer @@ -0,0 +1,5 @@ +[Sanitizer] Make SuppressionContext a singleton class, residing in sanitizer_common. + +Convert TSan and LSan to the new interface. More changes will follow: +1) "suppressions" should become a common runtime flag. +2) Code for parsing suppressions file should be moved to SuppressionContext::Init(). Index: zdesc.tsan =================================================================== --- /dev/null +++ zdesc.tsan @@ -0,0 +1,3 @@ +[TSan] Revert r212531 and r212532. + +They cause "check-tsan" command to hang. Details in r212532 review thread. Index: zdesc.ubsan =================================================================== --- /dev/null +++ zdesc.ubsan @@ -0,0 +1,4 @@ +[UBSan] Optionally report summary in UBSan error reports. + +By default summary is not printed if UBSan is run in a standalone mode, +but is printed if it's combined with another sanitizer (like ASan). Index: zdiff.d2178 =================================================================== --- /dev/null +++ zdiff.d2178 @@ -0,0 +1,202 @@ +Index: lib/ubsan/ubsan_handlers.cc +=================================================================== +--- lib/ubsan/ubsan_handlers.cc (revision 212963) ++++ lib/ubsan/ubsan_handlers.cc (working copy) +@@ -50,6 +50,7 @@ + << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; + if (Pointer) + Diag(Pointer, DL_Note, "pointer points here"); ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, + ValueHandle Pointer) { +@@ -74,6 +75,7 @@ + "%1 %2 %3 cannot be represented in type %4") + << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned") + << Value(Data->Type, LHS) << Operator << RHS << Data->Type; ++ ReportSummary(Loc); + } + + void __ubsan::__ubsan_handle_add_overflow(OverflowData *Data, +@@ -124,6 +126,7 @@ + Diag(Loc, DL_Error, + "negation of %0 cannot be represented in type %1") + << Value(Data->Type, OldVal) << Data->Type; ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, + ValueHandle OldVal) { +@@ -145,6 +148,7 @@ + << LHSVal << Data->Type; + else + Diag(Loc, DL_Error, "division by zero"); ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, + ValueHandle LHS, +@@ -174,6 +178,7 @@ + Diag(Loc, DL_Error, + "left shift of %0 by %1 places cannot be represented in type %2") + << LHSVal << RHSVal << Data->LHSType; ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( + ShiftOutOfBoundsData *Data, +@@ -192,6 +197,7 @@ + Value IndexVal(Data->IndexType, Index); + Diag(Loc, DL_Error, "index %0 out of bounds for type %1") + << IndexVal << Data->ArrayType; ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, + ValueHandle Index) { +@@ -200,14 +206,23 @@ + } + + void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { +- Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); ++ SourceLocation Loc = Data->Loc.acquire(); ++ if (Loc.isDisabled()) ++ return; ++ ++ Diag(Loc, DL_Error, "execution reached a __builtin_unreachable() call"); ++ ReportSummary(Loc); + Die(); + } + + void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { +- Diag(Data->Loc, DL_Error, +- "execution reached the end of a value-returning function " +- "without returning a value"); ++ SourceLocation Loc = Data->Loc.acquire(); ++ if (Loc.isDisabled()) ++ return; ++ ++ Diag(Loc, DL_Error, "execution reached the end of a value-returning function " ++ "without returning a value"); ++ ReportSummary(Loc); + Die(); + } + +@@ -220,6 +235,7 @@ + Diag(Loc, DL_Error, "variable length array bound evaluates to " + "non-positive value %0") + << Value(Data->Type, Bound); ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, + ValueHandle Bound) { +@@ -231,16 +247,20 @@ + void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data, + ValueHandle From) { + // TODO: Add deduplication once a SourceLocation is generated for this check. +- Diag(getCallerLocation(), DL_Error, ++ Location Loc = getCallerLocation(); ++ Diag(Loc, DL_Error, + "value %0 is outside the range of representable values of type %2") +- << Value(Data->FromType, From) << Data->FromType << Data->ToType; ++ << Value(Data->FromType, From) << Data->FromType << Data->ToType; ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_float_cast_overflow_abort( + FloatCastOverflowData *Data, + ValueHandle From) { +- Diag(getCallerLocation(), DL_Error, ++ Location Loc = getCallerLocation(); ++ Diag(Loc, DL_Error, + "value %0 is outside the range of representable values of type %2") +- << Value(Data->FromType, From) << Data->FromType << Data->ToType; ++ << Value(Data->FromType, From) << Data->FromType << Data->ToType; ++ ReportSummary(Loc); + Die(); + } + +@@ -253,6 +273,7 @@ + Diag(Loc, DL_Error, + "load of value %0, which is not a valid value for type %1") + << Value(Data->Type, Val) << Data->Type; ++ ReportSummary(Loc); + } + void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, + ValueHandle Val) { +@@ -271,6 +292,7 @@ + "call to function %0 through pointer to incorrect function type %1") + << FName << Data->Type; + Diag(Loc, DL_Note, "%0 defined here") << FName; ++ ReportSummary(Loc); + } + + void __ubsan::__ubsan_handle_function_type_mismatch_abort( +Index: lib/ubsan/ubsan_handlers_cxx.cc +=================================================================== +--- lib/ubsan/ubsan_handlers_cxx.cc (revision 212963) ++++ lib/ubsan/ubsan_handlers_cxx.cc (working copy) +@@ -60,6 +60,7 @@ + << MangledName(DTI.getSubobjectTypeName()) + << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1"); + ++ ReportSummary(Loc); + if (Abort) + Die(); + } +Index: lib/ubsan/ubsan_diag.cc +=================================================================== +--- lib/ubsan/ubsan_diag.cc (revision 212963) ++++ lib/ubsan/ubsan_diag.cc (working copy) +@@ -105,8 +105,7 @@ + #endif + } + +-static void renderLocation(Location Loc) { +- InternalScopedString LocBuffer(1024); ++static void renderLocation(Location Loc, InternalScopedString &LocBuffer) { + switch (Loc.getKind()) { + case Location::LK_Source: { + SourceLocation SLoc = Loc.getSourceLocation(); +@@ -128,7 +127,6 @@ + LocBuffer.append(""); + break; + } +- Printf("%s:", LocBuffer.data()); + } + + static void renderText(const char *Message, const Diag::Arg *Args) { +@@ -279,7 +277,9 @@ + SpinMutexLock l(&CommonSanitizerReportMutex); + Printf(Decor.Bold()); + +- renderLocation(Loc); ++ InternalScopedString LocBuffer(1024); ++ renderLocation(Loc, LocBuffer); ++ Printf("%s:", LocBuffer.data()); + + switch (Level) { + case DL_Error: +@@ -300,3 +300,13 @@ + renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, + NumRanges, Args); + } ++ ++void __ubsan::ReportSummary(Location Loc) { ++ InitializeSanitizerCommon(); ++ if (!common_flags()->print_summary) ++ return; ++ InternalScopedString SummaryBuffer(1024); ++ SummaryBuffer.append("runtime-error: "); ++ renderLocation(Loc, SummaryBuffer); ++ ReportErrorSummary(SummaryBuffer.data()); ++} +Index: lib/ubsan/ubsan_diag.h +=================================================================== +--- lib/ubsan/ubsan_diag.h (revision 212963) ++++ lib/ubsan/ubsan_diag.h (working copy) +@@ -203,6 +203,9 @@ + Diag &operator<<(const Range &R) { return AddRange(R); } + }; + ++/// Optionally constructs and reports SUMMARY line like another sanitizers. ++void ReportSummary(Location Loc); ++ + } // namespace __ubsan + + #endif // UBSAN_DIAG_H Index: zdiff.d4305 =================================================================== --- /dev/null +++ zdiff.d4305 @@ -0,0 +1,49 @@ +Index: lib/asan/asan_mac.cc +=================================================================== +--- lib/asan/asan_mac.cc ++++ lib/asan/asan_mac.cc +@@ -374,32 +374,44 @@ + work(); \ + } + ++// forces the compiler to generate a frame pointer in the calling function ++#define ENABLE_FRAME_POINTER \ ++ do { \ ++ volatile uptr enable_fp; \ ++ enable_fp = GET_CURRENT_FRAME(); \ ++ } while (0) ++ + INTERCEPTOR(void, dispatch_async, + dispatch_queue_t dq, void(^work)(void)) { ++ ENABLE_FRAME_POINTER; + GET_ASAN_BLOCK(work); + REAL(dispatch_async)(dq, asan_block); + } + + INTERCEPTOR(void, dispatch_group_async, + dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { ++ ENABLE_FRAME_POINTER; + GET_ASAN_BLOCK(work); + REAL(dispatch_group_async)(dg, dq, asan_block); + } + + INTERCEPTOR(void, dispatch_after, + dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { ++ ENABLE_FRAME_POINTER; + GET_ASAN_BLOCK(work); + REAL(dispatch_after)(when, queue, asan_block); + } + + INTERCEPTOR(void, dispatch_source_set_cancel_handler, + dispatch_source_t ds, void(^work)(void)) { ++ ENABLE_FRAME_POINTER; + GET_ASAN_BLOCK(work); + REAL(dispatch_source_set_cancel_handler)(ds, asan_block); + } + + INTERCEPTOR(void, dispatch_source_set_event_handler, + dispatch_source_t ds, void(^work)(void)) { ++ ENABLE_FRAME_POINTER; + GET_ASAN_BLOCK(work); + REAL(dispatch_source_set_event_handler)(ds, asan_block); + } Index: zdiff.d4692 =================================================================== --- /dev/null +++ zdiff.d4692 @@ -0,0 +1,105 @@ +Index: lib/sanitizer_common/sanitizer_stacktrace.cc +=================================================================== +--- lib/sanitizer_common/sanitizer_stacktrace.cc ++++ lib/sanitizer_common/sanitizer_stacktrace.cc +@@ -36,27 +36,47 @@ + return GET_CALLER_PC(); + } + ++// Check if given pointer points into allocated stack area. ++static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { ++ return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); ++} ++ ++// In GCC on ARM bp points to saved lr, not fp, so we should check the next ++// cell in stack to be a saved frame pointer. GetCanonicFrame returns the ++// pointer to saved frame pointer in any case. ++static inline uhwptr *GetCanonicFrame(uptr bp, ++ uptr stack_top, ++ uptr stack_bottom) { ++#ifdef __arm__ ++ if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; ++ uhwptr *bp_prev = (uhwptr *)bp; ++ if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; ++ return bp_prev - 1; ++#else ++ return (uhwptr*)bp; ++#endif ++} ++ + void StackTrace::FastUnwindStack(uptr pc, uptr bp, + uptr stack_top, uptr stack_bottom, + uptr max_depth) { + CHECK_GE(max_depth, 2); + trace[0] = pc; + size = 1; +- uhwptr *frame = (uhwptr *)bp; +- uhwptr *prev_frame = frame - 1; + if (stack_top < 4096) return; // Sanity check for stack top. ++ uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); ++ uhwptr *prev_frame = 0; + // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. + while (frame > prev_frame && +- frame < (uhwptr *)stack_top - 2 && +- frame > (uhwptr *)stack_bottom && ++ IsValidFrame((uptr)frame, stack_top, stack_bottom) && + IsAligned((uptr)frame, sizeof(*frame)) && + size < max_depth) { + uhwptr pc1 = frame[1]; + if (pc1 != pc) { + trace[size++] = (uptr) pc1; + } + prev_frame = frame; +- frame = (uhwptr *)frame[0]; ++ frame = GetCanonicFrame((uptr)frame[0], stack_top, stack_bottom); + } + } + +Index: test/asan/TestCases/Linux/clang_gcc_abi.cc +=================================================================== +--- test/asan/TestCases/Linux/clang_gcc_abi.cc ++++ test/asan/TestCases/Linux/clang_gcc_abi.cc +@@ -0,0 +1,43 @@ ++// RUN: %clangxx_asan -O0 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s ++// RUN: %clangxx_asan -O1 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s ++// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s ++// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s ++ ++// REQUIRES: arm-supported-target ++ ++#include ++ ++int boom() { ++ volatile int three = 3; ++ char *s = (char *)malloc(three); ++// CHECK: #1 0x{{.*}} in boom {{.*}}clang_gcc_abi.cc:[[@LINE-1]] ++ return s[three]; //BOOM ++} ++ ++__attribute__((naked, noinline)) void gcc_abi() { ++// CHECK: #2 0x{{.*}} in gcc_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]] ++ asm volatile("str fp, [sp, #-8]!\n\t" ++ "str lr, [sp, #4]\n\t" ++ "add fp, sp, #4\n\t" ++ "bl boom\n\t" ++ "sub sp, fp, #4\n\t" ++ "ldr fp, [sp]\n\t" ++ "add sp, sp, #4\n\t" ++ "ldr pc, [sp], #4\n\t" ++ ); ++} ++ ++__attribute__((naked, noinline)) void clang_abi() { ++// CHECK: #3 0x{{.*}} in clang_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]] ++ asm volatile("push {r11, lr}\n\t" ++ "mov r11, sp\n\t" ++ "bl gcc_abi\n\t" ++ "add r0, r0, #1\n\t" ++ "pop {r11, pc}\n\t" ++ ); ++} ++ ++int main() { ++ clang_abi(); ++// CHECK: #4 0x{{.*}} in main {{.*}}clang_gcc_abi.cc:[[@LINE-1]] ++} Index: zdiff.d4703 =================================================================== --- /dev/null +++ zdiff.d4703 @@ -0,0 +1,127 @@ +Index: lib/asan/scripts/asan_symbolize.py +=================================================================== +--- lib/asan/scripts/asan_symbolize.py ++++ lib/asan/scripts/asan_symbolize.py +@@ -7,6 +7,7 @@ + # License. See LICENSE.TXT for details. + # + #===------------------------------------------------------------------------===# ++import argparse + import bisect + import getopt + import os +@@ -18,18 +19,26 @@ + + symbolizers = {} + DEBUG = False +-demangle = False; +- ++demangle = False ++binutils_prefix = None ++sysroot_path = None ++binary_name_filter = None ++fix_filename_patterns = None ++logfile = None + + # FIXME: merge the code that calls fix_filename(). + def fix_filename(file_name): +- for path_to_cut in sys.argv[1:]: +- file_name = re.sub('.*' + path_to_cut, '', file_name) ++ if fix_filename_patterns: ++ for path_to_cut in fix_filename_patterns: ++ file_name = re.sub('.*' + path_to_cut, '', file_name) + file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name) + file_name = re.sub('.*crtstuff.c:0', '???:0', file_name) + return file_name + +-def GuessArch(addr): ++def sysroot_path_filter(binary_name): ++ return sysroot_path + binary_name ++ ++def guess_arch(addr): + # Guess which arch we're running. 10 = len('0x') + 8 hex digits. + if len(addr) > 10: + return 'x86_64' +@@ -60,7 +69,7 @@ + def __init__(self, symbolizer_path, addr): + super(LLVMSymbolizer, self).__init__() + self.symbolizer_path = symbolizer_path +- self.default_arch = GuessArch(addr) ++ self.default_arch = guess_arch(addr) + self.pipe = self.open_llvm_symbolizer() + + def open_llvm_symbolizer(self): +@@ -124,7 +133,10 @@ + self.pipe = self.open_addr2line() + + def open_addr2line(self): +- cmd = ['addr2line', '-f'] ++ addr2line_tool = 'addr2line' ++ if binutils_prefix: ++ addr2line_tool = binutils_prefix + addr2line_tool ++ cmd = [addr2line_tool, '-f'] + if demangle: + cmd += ['--demangle'] + cmd += ['-e', self.binary] +@@ -182,7 +194,7 @@ + def __init__(self, addr, binary): + super(DarwinSymbolizer, self).__init__() + self.binary = binary +- self.arch = GuessArch(addr) ++ self.arch = guess_arch(addr) + self.open_atos() + + def open_atos(self): +@@ -363,10 +375,10 @@ + self.frame_no += 1 + return result + +- def process_stdin(self): ++ def process_logfile(self): + self.frame_no = 0 + while True: +- line = sys.stdin.readline() ++ line = logfile.readline() + if not line: + break + processed = self.process_line(line) +@@ -397,9 +409,33 @@ + + + if __name__ == '__main__': +- opts, args = getopt.getopt(sys.argv[1:], "d", ["demangle"]) +- for o, a in opts: +- if o in ("-d", "--demangle"): +- demangle = True; +- loop = SymbolizationLoop() +- loop.process_stdin() ++ parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, ++ description='ASan symbolization script', ++ epilog='''Example of use: ++ asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" -s "$HOME/SymbolFiles" < asan.log''') ++ parser.add_argument('path_to_cut', nargs='*', ++ help='pattern to be cut from the result file path ') ++ parser.add_argument('-d','--demangle', action='store_true', ++ help='demangle function names') ++ parser.add_argument('-s', metavar='SYSROOT', ++ help='set path to sysroot for sanitized binaries') ++ parser.add_argument('-c', metavar='CROSS_COMPILE', ++ help='set prefix for binutils') ++ parser.add_argument('-l','--logfile', default=sys.stdin, type=argparse.FileType('r'), ++ help='set log file name to parse, default is stdin') ++ args = parser.parse_args() ++ if args.path_to_cut: ++ fix_filename_patterns = args.path_to_cut ++ if args.demangle: ++ demangle = True ++ if args.s: ++ binary_name_filter = sysroot_path_filter ++ sysroot_path = args.s ++ if args.c: ++ binutils_prefix = args.c ++ if args.logfile: ++ logfile = args.logfile ++ else: ++ logfile = sys.stdin ++ loop = SymbolizationLoop(binary_name_filter) ++ loop.process_logfile() Index: zdiff.jakub_ubsan =================================================================== --- /dev/null +++ zdiff.jakub_ubsan @@ -0,0 +1,57 @@ +--- libsanitizer/ubsan/ubsan_handlers.cc.jj 2013-12-05 12:04:32.000000000 +0100 ++++ libsanitizer/ubsan/ubsan_handlers.cc 2014-06-26 17:03:48.018251367 +0200 +@@ -277,3 +277,31 @@ void __ubsan::__ubsan_handle_function_ty + __ubsan_handle_function_type_mismatch(Data, Function); + Die(); + } ++ ++void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data, uptr ArgNo) { ++ SourceLocation Loc = Data->Loc.acquire(); ++ if (Loc.isDisabled()) ++ return; ++ ++ Diag(Loc, DL_Error, "null argument where non-null required " ++ "(argument %0)") << ArgNo; ++} ++ ++void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data, ++ uptr ArgNo) { ++ __ubsan::__ubsan_handle_nonnull_arg(Data, ArgNo); ++ Die(); ++} ++ ++void __ubsan::__ubsan_handle_nonnull_return(NonNullRetData *Data) { ++ SourceLocation Loc = Data->Loc.acquire(); ++ if (Loc.isDisabled()) ++ return; ++ ++ Diag(Loc, DL_Error, "null return value where non-null required"); ++} ++ ++void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullRetData *Data) { ++ __ubsan::__ubsan_handle_nonnull_return(Data); ++ Die(); ++} +--- libsanitizer/ubsan/ubsan_handlers.h.jj 2013-12-05 12:04:32.000000000 +0100 ++++ libsanitizer/ubsan/ubsan_handlers.h 2014-06-26 17:02:03.330803480 +0200 +@@ -119,6 +119,20 @@ RECOVERABLE(function_type_mismatch, + FunctionTypeMismatchData *Data, + ValueHandle Val) + ++struct NonNullArgData { ++ SourceLocation Loc; ++}; ++ ++/// \brief Handle passing null to function argument with nonnull attribute. ++RECOVERABLE(nonnull_arg, NonNullArgData *Data, uptr ArgNo) ++ ++struct NonNullRetData { ++ SourceLocation Loc; ++}; ++ ++/// \brief Handle returning null from function with returns_nonnull attribute. ++RECOVERABLE(nonnull_return, NonNullRetData *Data) ++ + } + + #endif // UBSAN_HANDLERS_H Index: zdiff.r209897 =================================================================== --- /dev/null +++ zdiff.r209897 @@ -0,0 +1,538 @@ +Index: lib/tsan/rtl/tsan_rtl.cc +=================================================================== +--- lib/tsan/rtl/tsan_rtl.cc (revision 209897) ++++ lib/tsan/rtl/tsan_rtl.cc (revision 209896) +@@ -25,16 +25,6 @@ + #include "tsan_suppressions.h" + #include "tsan_symbolize.h" + +-#ifdef __SSE3__ +-// transitively includes , +-// and it's prohibited to include std headers into tsan runtime. +-// So we do this dirty trick. +-#define _MM_MALLOC_H_INCLUDED +-#define __MM_MALLOC_H +-#include +-typedef __m128i m128; +-#endif +- + volatile int __tsan_resumed = 0; + + extern "C" void __tsan_resume() { +@@ -481,8 +471,7 @@ + *s = 0; + } + +-ALWAYS_INLINE +-void HandleRace(ThreadState *thr, u64 *shadow_mem, ++static inline void HandleRace(ThreadState *thr, u64 *shadow_mem, + Shadow cur, Shadow old) { + thr->racy_state[0] = cur.raw(); + thr->racy_state[1] = old.raw(); +@@ -494,12 +483,16 @@ + #endif + } + ++static inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) { ++ return old.epoch() >= thr->fast_synch_epoch; ++} ++ + static inline bool HappensBefore(Shadow old, ThreadState *thr) { + return thr->clock.get(old.TidWithIgnore()) >= old.epoch(); + } + +-ALWAYS_INLINE +-void MemoryAccessImpl1(ThreadState *thr, uptr addr, ++ALWAYS_INLINE USED ++void MemoryAccessImpl(ThreadState *thr, uptr addr, + int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, + u64 *shadow_mem, Shadow cur) { + StatInc(thr, StatMop); +@@ -593,90 +586,6 @@ + } + } + +-ALWAYS_INLINE +-bool ContainsSameAccessSlow(u64 *s, u64 a, u64 sync_epoch, bool is_write) { +- Shadow cur(a); +- for (uptr i = 0; i < kShadowCnt; i++) { +- Shadow old(LoadShadow(&s[i])); +- if (Shadow::Addr0AndSizeAreEqual(cur, old) && +- old.TidWithIgnore() == cur.TidWithIgnore() && +- old.epoch() > sync_epoch && +- old.IsAtomic() == cur.IsAtomic() && +- old.IsRead() <= cur.IsRead()) +- return true; +- } +- return false; +-} +- +-#if defined(__SSE3__) && TSAN_SHADOW_COUNT == 4 +-#define SHUF(v0, v1, i0, i1, i2, i3) _mm_castps_si128(_mm_shuffle_ps( \ +- _mm_castsi128_ps(v0), _mm_castsi128_ps(v1), \ +- (i0)*1 + (i1)*4 + (i2)*16 + (i3)*64)) +-ALWAYS_INLINE +-bool ContainsSameAccessFast(u64 *s, u64 a, u64 sync_epoch, bool is_write) { +- // This is an optimized version of ContainsSameAccessSlow. +- // load current access into access[0:63] +- const m128 access = _mm_cvtsi64_si128(a); +- // duplicate high part of access in addr0: +- // addr0[0:31] = access[32:63] +- // addr0[32:63] = access[32:63] +- // addr0[64:95] = access[32:63] +- // addr0[96:127] = access[32:63] +- const m128 addr0 = SHUF(access, access, 1, 1, 1, 1); +- // load 4 shadow slots +- const m128 shadow0 = _mm_load_si128((__m128i*)s); +- const m128 shadow1 = _mm_load_si128((__m128i*)s + 1); +- // load high parts of 4 shadow slots into addr_vect: +- // addr_vect[0:31] = shadow0[32:63] +- // addr_vect[32:63] = shadow0[96:127] +- // addr_vect[64:95] = shadow1[32:63] +- // addr_vect[96:127] = shadow1[96:127] +- m128 addr_vect = SHUF(shadow0, shadow1, 1, 3, 1, 3); +- if (!is_write) { +- // set IsRead bit in addr_vect +- const m128 rw_mask1 = _mm_cvtsi64_si128(1<<15); +- const m128 rw_mask = SHUF(rw_mask1, rw_mask1, 0, 0, 0, 0); +- addr_vect = _mm_or_si128(addr_vect, rw_mask); +- } +- // addr0 == addr_vect? +- const m128 addr_res = _mm_cmpeq_epi32(addr0, addr_vect); +- // epoch1[0:63] = sync_epoch +- const m128 epoch1 = _mm_cvtsi64_si128(sync_epoch); +- // epoch[0:31] = sync_epoch[0:31] +- // epoch[32:63] = sync_epoch[0:31] +- // epoch[64:95] = sync_epoch[0:31] +- // epoch[96:127] = sync_epoch[0:31] +- const m128 epoch = SHUF(epoch1, epoch1, 0, 0, 0, 0); +- // load low parts of shadow cell epochs into epoch_vect: +- // epoch_vect[0:31] = shadow0[0:31] +- // epoch_vect[32:63] = shadow0[64:95] +- // epoch_vect[64:95] = shadow1[0:31] +- // epoch_vect[96:127] = shadow1[64:95] +- const m128 epoch_vect = SHUF(shadow0, shadow1, 0, 2, 0, 2); +- // epoch_vect >= sync_epoch? +- const m128 epoch_res = _mm_cmpgt_epi32(epoch_vect, epoch); +- // addr_res & epoch_res +- const m128 res = _mm_and_si128(addr_res, epoch_res); +- // mask[0] = res[7] +- // mask[1] = res[15] +- // ... +- // mask[15] = res[127] +- const int mask = _mm_movemask_epi8(res); +- return mask != 0; +-} +-#endif +- +-ALWAYS_INLINE +-bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) { +-#if defined(__SSE3__) && TSAN_SHADOW_COUNT == 4 +- bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write); +- DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write)); +- return res; +-#else +- return ContainsSameAccessSlow(s, a, sync_epoch, is_write); +-#endif +-} +- + ALWAYS_INLINE USED + void MemoryAccess(ThreadState *thr, uptr pc, uptr addr, + int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) { +@@ -709,12 +618,14 @@ + } + + FastState fast_state = thr->fast_state; +- if (fast_state.GetIgnoreBit()) { +- StatInc(thr, StatMop); +- StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); +- StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); +- StatInc(thr, StatMopIgnored); ++ if (fast_state.GetIgnoreBit()) + return; ++ if (kCollectHistory) { ++ fast_state.IncrementEpoch(); ++ thr->fast_state = fast_state; ++ // We must not store to the trace if we do not store to the shadow. ++ // That is, this call must be moved somewhere below. ++ TraceAddEvent(thr, fast_state, EventTypeMop, pc); + } + + Shadow cur(fast_state); +@@ -722,43 +633,10 @@ + cur.SetWrite(kAccessIsWrite); + cur.SetAtomic(kIsAtomic); + +- if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(), +- thr->fast_synch_epoch, kAccessIsWrite))) { +- StatInc(thr, StatMop); +- StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); +- StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); +- StatInc(thr, StatMopSame); +- return; +- } +- +- if (kCollectHistory) { +- fast_state.IncrementEpoch(); +- TraceAddEvent(thr, fast_state, EventTypeMop, pc); +- thr->fast_state = fast_state; +- cur.IncrementEpoch(); +- } +- +- MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, ++ MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, + shadow_mem, cur); + } + +-// Called by MemoryAccessRange in tsan_rtl_thread.cc +-void MemoryAccessImpl(ThreadState *thr, uptr addr, +- int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, +- u64 *shadow_mem, Shadow cur) { +- if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(), +- thr->fast_synch_epoch, kAccessIsWrite))) { +- StatInc(thr, StatMop); +- StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); +- StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); +- StatInc(thr, StatMopSame); +- return; +- } +- +- MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, +- shadow_mem, cur); +-} +- + static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size, + u64 val) { + (void)thr; +Index: lib/tsan/rtl/tsan_rtl.h +=================================================================== +--- lib/tsan/rtl/tsan_rtl.h (revision 209897) ++++ lib/tsan/rtl/tsan_rtl.h (revision 209896) +@@ -78,14 +78,14 @@ + // FastState (from most significant bit): + // ignore : 1 + // tid : kTidBits ++// epoch : kClkBits + // unused : - + // history_size : 3 +-// epoch : kClkBits + class FastState { + public: + FastState(u64 tid, u64 epoch) { + x_ = tid << kTidShift; +- x_ |= epoch; ++ x_ |= epoch << kClkShift; + DCHECK_EQ(tid, this->tid()); + DCHECK_EQ(epoch, this->epoch()); + DCHECK_EQ(GetIgnoreBit(), false); +@@ -110,13 +110,13 @@ + } + + u64 epoch() const { +- u64 res = x_ & ((1ull << kClkBits) - 1); ++ u64 res = (x_ << (kTidBits + 1)) >> (64 - kClkBits); + return res; + } + + void IncrementEpoch() { + u64 old_epoch = epoch(); +- x_ += 1; ++ x_ += 1 << kClkShift; + DCHECK_EQ(old_epoch + 1, epoch()); + (void)old_epoch; + } +@@ -128,19 +128,17 @@ + void SetHistorySize(int hs) { + CHECK_GE(hs, 0); + CHECK_LE(hs, 7); +- x_ = (x_ & ~(kHistoryMask << kHistoryShift)) | (u64(hs) << kHistoryShift); ++ x_ = (x_ & ~7) | hs; + } + +- ALWAYS_INLINE + int GetHistorySize() const { +- return (int)((x_ >> kHistoryShift) & kHistoryMask); ++ return (int)(x_ & 7); + } + + void ClearHistorySize() { +- SetHistorySize(0); ++ x_ &= ~7; + } + +- ALWAYS_INLINE + u64 GetTracePos() const { + const int hs = GetHistorySize(); + // When hs == 0, the trace consists of 2 parts. +@@ -151,21 +149,20 @@ + private: + friend class Shadow; + static const int kTidShift = 64 - kTidBits - 1; ++ static const int kClkShift = kTidShift - kClkBits; + static const u64 kIgnoreBit = 1ull << 63; + static const u64 kFreedBit = 1ull << 63; +- static const u64 kHistoryShift = kClkBits; +- static const u64 kHistoryMask = 7; + u64 x_; + }; + + // Shadow (from most significant bit): + // freed : 1 + // tid : kTidBits ++// epoch : kClkBits + // is_atomic : 1 + // is_read : 1 + // size_log : 2 + // addr0 : 3 +-// epoch : kClkBits + class Shadow : public FastState { + public: + explicit Shadow(u64 x) +@@ -178,10 +175,10 @@ + } + + void SetAddr0AndSizeLog(u64 addr0, unsigned kAccessSizeLog) { +- DCHECK_EQ((x_ >> kClkBits) & 31, 0); ++ DCHECK_EQ(x_ & 31, 0); + DCHECK_LE(addr0, 7); + DCHECK_LE(kAccessSizeLog, 3); +- x_ |= ((kAccessSizeLog << 3) | addr0) << kClkBits; ++ x_ |= (kAccessSizeLog << 3) | addr0; + DCHECK_EQ(kAccessSizeLog, size_log()); + DCHECK_EQ(addr0, this->addr0()); + } +@@ -214,34 +211,47 @@ + return shifted_xor == 0; + } + +- static ALWAYS_INLINE +- bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) { +- u64 masked_xor = ((s1.x_ ^ s2.x_) >> kClkBits) & 31; ++ static inline bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) { ++ u64 masked_xor = (s1.x_ ^ s2.x_) & 31; + return masked_xor == 0; + } + +- static ALWAYS_INLINE bool TwoRangesIntersect(Shadow s1, Shadow s2, ++ static inline bool TwoRangesIntersect(Shadow s1, Shadow s2, + unsigned kS2AccessSize) { + bool res = false; + u64 diff = s1.addr0() - s2.addr0(); + if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // NOLINT + // if (s1.addr0() + size1) > s2.addr0()) return true; +- if (s1.size() > -diff) +- res = true; ++ if (s1.size() > -diff) res = true; + } else { + // if (s2.addr0() + kS2AccessSize > s1.addr0()) return true; +- if (kS2AccessSize > diff) +- res = true; ++ if (kS2AccessSize > diff) res = true; + } +- DCHECK_EQ(res, TwoRangesIntersectSlow(s1, s2)); +- DCHECK_EQ(res, TwoRangesIntersectSlow(s2, s1)); ++ DCHECK_EQ(res, TwoRangesIntersectSLOW(s1, s2)); ++ DCHECK_EQ(res, TwoRangesIntersectSLOW(s2, s1)); + return res; + } + +- u64 ALWAYS_INLINE addr0() const { return (x_ >> kClkBits) & 7; } +- u64 ALWAYS_INLINE size() const { return 1ull << size_log(); } +- bool ALWAYS_INLINE IsWrite() const { return !IsRead(); } +- bool ALWAYS_INLINE IsRead() const { return x_ & kReadBit; } ++ // The idea behind the offset is as follows. ++ // Consider that we have 8 bool's contained within a single 8-byte block ++ // (mapped to a single shadow "cell"). Now consider that we write to the bools ++ // from a single thread (which we consider the common case). ++ // W/o offsetting each access will have to scan 4 shadow values at average ++ // to find the corresponding shadow value for the bool. ++ // With offsetting we start scanning shadow with the offset so that ++ // each access hits necessary shadow straight off (at least in an expected ++ // optimistic case). ++ // This logic works seamlessly for any layout of user data. For example, ++ // if user data is {int, short, char, char}, then accesses to the int are ++ // offsetted to 0, short - 4, 1st char - 6, 2nd char - 7. Hopefully, accesses ++ // from a single thread won't need to scan all 8 shadow values. ++ unsigned ComputeSearchOffset() { ++ return x_ & 7; ++ } ++ u64 addr0() const { return x_ & 7; } ++ u64 size() const { return 1ull << size_log(); } ++ bool IsWrite() const { return !IsRead(); } ++ bool IsRead() const { return x_ & kReadBit; } + + // The idea behind the freed bit is as follows. + // When the memory is freed (or otherwise unaccessible) we write to the shadow +@@ -266,14 +276,15 @@ + return res; + } + +- bool ALWAYS_INLINE IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const { +- bool v = x_ & ((u64(kIsWrite ^ 1) << kReadShift) +- | (u64(kIsAtomic) << kAtomicShift)); ++ bool IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const { ++ // analyzes 5-th bit (is_read) and 6-th bit (is_atomic) ++ bool v = x_ & u64(((kIsWrite ^ 1) << kReadShift) ++ | (kIsAtomic << kAtomicShift)); + DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic)); + return v; + } + +- bool ALWAYS_INLINE IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const { ++ bool IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const { + bool v = ((x_ >> kReadShift) & 3) + <= u64((kIsWrite ^ 1) | (kIsAtomic << 1)); + DCHECK_EQ(v, (IsAtomic() < kIsAtomic) || +@@ -281,7 +292,7 @@ + return v; + } + +- bool ALWAYS_INLINE IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const { ++ bool IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const { + bool v = ((x_ >> kReadShift) & 3) + >= u64((kIsWrite ^ 1) | (kIsAtomic << 1)); + DCHECK_EQ(v, (IsAtomic() > kIsAtomic) || +@@ -290,14 +301,14 @@ + } + + private: +- static const u64 kReadShift = 5 + kClkBits; ++ static const u64 kReadShift = 5; + static const u64 kReadBit = 1ull << kReadShift; +- static const u64 kAtomicShift = 6 + kClkBits; ++ static const u64 kAtomicShift = 6; + static const u64 kAtomicBit = 1ull << kAtomicShift; + +- u64 size_log() const { return (x_ >> (3 + kClkBits)) & 3; } ++ u64 size_log() const { return (x_ >> 3) & 3; } + +- static bool TwoRangesIntersectSlow(const Shadow s1, const Shadow s2) { ++ static bool TwoRangesIntersectSLOW(const Shadow s1, const Shadow s2) { + if (s1.addr0() == s2.addr0()) return true; + if (s1.addr0() < s2.addr0() && s1.addr0() + s1.size() > s2.addr0()) + return true; +Index: lib/tsan/rtl/tsan_defs.h +=================================================================== +--- lib/tsan/rtl/tsan_defs.h (revision 209897) ++++ lib/tsan/rtl/tsan_defs.h (revision 209896) +@@ -54,7 +54,6 @@ + # endif + #else + // Count of shadow values in a shadow cell. +-#define TSAN_SHADOW_COUNT 4 + const uptr kShadowCnt = 4; + #endif + +Index: lib/tsan/rtl/tsan_stat.cc +=================================================================== +--- lib/tsan/rtl/tsan_stat.cc (revision 209897) ++++ lib/tsan/rtl/tsan_stat.cc (revision 209896) +@@ -37,7 +37,6 @@ + name[StatMop4] = " size 4 "; + name[StatMop8] = " size 8 "; + name[StatMopSame] = " Including same "; +- name[StatMopIgnored] = " Including ignored "; + name[StatMopRange] = " Including range "; + name[StatMopRodata] = " Including .rodata "; + name[StatMopRangeRodata] = " Including .rodata range "; +Index: lib/tsan/rtl/tsan_stat.h +=================================================================== +--- lib/tsan/rtl/tsan_stat.h (revision 209897) ++++ lib/tsan/rtl/tsan_stat.h (revision 209896) +@@ -26,7 +26,6 @@ + StatMop4, + StatMop8, + StatMopSame, +- StatMopIgnored, + StatMopRange, + StatMopRodata, + StatMopRangeRodata, +Index: lib/tsan/rtl/tsan_update_shadow_word_inl.h +=================================================================== +--- lib/tsan/rtl/tsan_update_shadow_word_inl.h (revision 209897) ++++ lib/tsan/rtl/tsan_update_shadow_word_inl.h (revision 209896) +@@ -16,7 +16,8 @@ + do { + StatInc(thr, StatShadowProcessed); + const unsigned kAccessSize = 1 << kAccessSizeLog; +- u64 *sp = &shadow_mem[idx]; ++ unsigned off = cur.ComputeSearchOffset(); ++ u64 *sp = &shadow_mem[(idx + off) % kShadowCnt]; + old = LoadShadow(sp); + if (old.IsZero()) { + StatInc(thr, StatShadowZero); +@@ -32,6 +33,16 @@ + // same thread? + if (Shadow::TidsAreEqual(old, cur)) { + StatInc(thr, StatShadowSameThread); ++ if (OldIsInSameSynchEpoch(old, thr)) { ++ if (old.IsRWNotWeaker(kAccessIsWrite, kIsAtomic)) { ++ // found a slot that holds effectively the same info ++ // (that is, same tid, same sync epoch and same size) ++ StatInc(thr, StatMopSame); ++ return; ++ } ++ StoreIfNotYetStored(sp, &store_word); ++ break; ++ } + if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic)) + StoreIfNotYetStored(sp, &store_word); + break; +Index: lib/tsan/tests/unit/tsan_mman_test.cc +=================================================================== +--- lib/tsan/tests/unit/tsan_mman_test.cc (revision 209897) ++++ lib/tsan/tests/unit/tsan_mman_test.cc (revision 209896) +@@ -144,11 +144,6 @@ + } + + TEST(Mman, CallocOverflow) { +-#if TSAN_DEBUG +- // EXPECT_DEATH clones a thread with 4K stack, +- // which is overflown by tsan memory accesses functions in debug mode. +- return; +-#endif + size_t kArraySize = 4096; + volatile size_t kMaxSizeT = std::numeric_limits::max(); + volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; +Index: lib/tsan/check_analyze.sh +=================================================================== +--- lib/tsan/check_analyze.sh (revision 209897) ++++ lib/tsan/check_analyze.sh (revision 209896) +@@ -8,11 +8,11 @@ + + PrintRes + +-wmops="write1 \ ++mops="write1 \ + write2 \ + write4 \ +- write8" +-rmops="read1 \ ++ write8 \ ++ read1 \ + read2 \ + read4 \ + read8" +@@ -27,18 +27,12 @@ + fi + } + +-for f in $wmops; do +- check $f rsp 3 +- check $f push 1 +- check $f pop 5 ++for f in $mops; do ++ check $f rsp 1 # To read caller pc. ++ check $f push 0 ++ check $f pop 0 + done + +-for f in $rmops; do +- check $f rsp 3 +- check $f push 1 +- check $f pop 4 +-done +- + for f in $func; do + check $f rsp 0 + check $f push 0 Index: zdiff.ubsan =================================================================== --- /dev/null +++ zdiff.ubsan @@ -0,0 +1,89 @@ +Index: lib/ubsan/ubsan_diag.cc +=================================================================== +--- lib/ubsan/ubsan_diag.cc (revision 217535) ++++ lib/ubsan/ubsan_diag.cc (working copy) +@@ -193,28 +193,44 @@ + return Best; + } + ++static inline MemoryLocation subtractNoOverflow(uptr LHS, uptr RHS) { ++ return (LHS < RHS) ? 0 : LHS - RHS; ++} ++ ++static inline MemoryLocation addNoOverflow(uptr LHS, uptr RHS) { ++ const uptr Limit = (uptr)-1; ++ return (LHS > Limit - RHS) ? Limit : LHS + RHS; ++} ++ + /// Render a snippet of the address space near a location. + static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc, + Range *Ranges, unsigned NumRanges, + const Diag::Arg *Args) { +- const unsigned BytesToShow = 32; + const unsigned MinBytesNearLoc = 4; + + // Show at least the 8 bytes surrounding Loc. +- MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc; ++ MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc); ++ MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc); ++ MemoryLocation OrigMin = Min; + for (unsigned I = 0; I < NumRanges; ++I) { + Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); + Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); + } + + // If we have too many interesting bytes, prefer to show bytes after Loc. ++ const unsigned BytesToShow = 32; + if (Max - Min > BytesToShow) +- Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc); +- Max = Min + BytesToShow; ++ Min = __sanitizer::Min(Max - BytesToShow, OrigMin); ++ Max = addNoOverflow(Min, BytesToShow); + ++ // Don't print the contents of inaccessible memory. ++ if (!IsAccessibleMemoryRange(Min, Max - Min)) { ++ Printf("\n"); ++ return; ++ } ++ + // Emit data. + for (uptr P = Min; P != Max; ++P) { +- // FIXME: Check that the address is readable before printing it. + unsigned char C = *reinterpret_cast(P); + Printf("%s%02x", (P % 8 == 0) ? " " : " ", C); + } +Index: test/ubsan/TestCases/TypeCheck/misaligned.cpp +=================================================================== +--- test/ubsan/TestCases/TypeCheck/misaligned.cpp (revision 217515) ++++ test/ubsan/TestCases/TypeCheck/misaligned.cpp (working copy) +@@ -8,6 +8,9 @@ + // RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW + // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD + ++// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t ++// RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD ++ + #include + + struct S { +@@ -23,6 +26,8 @@ + int *p = (int*)&c[4 + argv[1][1] - '0']; + S *s = (S*)p; + ++ void *wild = reinterpret_cast(0x123L); ++ + (void)*p; // ok! + + switch (argv[1][0]) { +@@ -74,5 +79,11 @@ + // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}} + // CHECK-NEW-NEXT: {{^ \^}} + return (new (s) S)->k && 0; ++ ++ case 'w': ++ // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment ++ // CHECK-WILD-NEXT: 0x000000000123: note: pointer points here ++ // CHECK-WILD-NEXT: ++ return static_cast(wild)->k; + } + } Index: zdiff.ubsan-summary =================================================================== --- /dev/null +++ zdiff.ubsan-summary @@ -0,0 +1,246 @@ +Index: lib/ubsan/ubsan_handlers_cxx.cc +=================================================================== +--- lib/ubsan/ubsan_handlers_cxx.cc (revision 218129) ++++ lib/ubsan/ubsan_handlers_cxx.cc (working copy) +@@ -44,7 +44,7 @@ + if (Loc.isDisabled()) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, + "%0 address %1 which does not point to an object of type %2") +Index: lib/ubsan/ubsan_handlers.cc +=================================================================== +--- lib/ubsan/ubsan_handlers.cc (revision 218129) ++++ lib/ubsan/ubsan_handlers.cc (working copy) +@@ -43,11 +43,11 @@ + if (ignoreReport(Loc.getSourceLocation(), Opts)) + return; + +- ScopedReport R(Opts); +- + if (Data->Loc.isInvalid()) + Loc = FallbackLoc; + ++ ScopedReport R(Opts, Loc); ++ + if (!Pointer) + Diag(Loc, DL_Error, "%0 null pointer of type %1") + << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; +@@ -85,7 +85,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "%0 integer overflow: " + "%1 %2 %3 cannot be represented in type %4") +@@ -114,7 +114,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + if (Data->Type.isSignedIntegerTy()) + Diag(Loc, DL_Error, +@@ -145,7 +145,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Value LHSVal(Data->Type, LHS); + Value RHSVal(Data->Type, RHS); +@@ -177,7 +177,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Value LHSVal(Data->LHSType, LHS); + Value RHSVal(Data->RHSType, RHS); +@@ -216,7 +216,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Value IndexVal(Data->IndexType, Index); + Diag(Loc, DL_Error, "index %0 out of bounds for type %1") +@@ -237,7 +237,7 @@ + + static void handleBuiltinUnreachableImpl(UnreachableData *Data, + ReportOptions Opts) { +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Data->Loc); + Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); + } + +@@ -248,7 +248,7 @@ + } + + static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Data->Loc); + Diag(Data->Loc, DL_Error, + "execution reached the end of a value-returning function " + "without returning a value"); +@@ -266,7 +266,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "variable length array bound evaluates to " + "non-positive value %0") +@@ -288,11 +288,12 @@ + static void handleFloatCastOverflow(FloatCastOverflowData *Data, + ValueHandle From, ReportOptions Opts) { + // TODO: Add deduplication once a SourceLocation is generated for this check. +- ScopedReport R(Opts); ++ Location Loc = getCallerLocation(); ++ ScopedReport R(Opts, Loc); + +- Diag(getCallerLocation(), DL_Error, ++ Diag(Loc, DL_Error, + "value %0 is outside the range of representable values of type %2") +- << Value(Data->FromType, From) << Data->FromType << Data->ToType; ++ << Value(Data->FromType, From) << Data->FromType << Data->ToType; + } + + void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data, +@@ -314,7 +315,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, + "load of value %0, which is not a valid value for type %1") +@@ -340,7 +341,7 @@ + + Location Loc = getFunctionLocation(Function, &FName); + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Data->Loc, DL_Error, + "call to function %0 through pointer to incorrect function type %1") +@@ -367,7 +368,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "null pointer returned from function declared to never " + "return null"); +@@ -391,7 +392,7 @@ + if (ignoreReport(Loc, Opts)) + return; + +- ScopedReport R(Opts); ++ ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " + "never be null") << Data->ArgIndex; +Index: lib/ubsan/ubsan_diag.cc +=================================================================== +--- lib/ubsan/ubsan_diag.cc (revision 218129) ++++ lib/ubsan/ubsan_diag.cc (working copy) +@@ -38,6 +38,22 @@ + stack.Print(); + } + ++static void MaybeReportErrorSummary(Location Loc) { ++ if (!common_flags()->print_summary) ++ return; ++ // Don't try to unwind the stack trace in UBSan summaries: just use the ++ // provided location. ++ if (Loc.isSourceLocation()) { ++ SourceLocation SLoc = Loc.getSourceLocation(); ++ if (!SLoc.isInvalid()) { ++ ReportErrorSummary("runtime-error", SLoc.getFilename(), SLoc.getLine(), ++ ""); ++ return; ++ } ++ } ++ ReportErrorSummary("runtime-error"); ++} ++ + namespace { + class Decorator : public SanitizerCommonDecorator { + public: +@@ -315,13 +331,15 @@ + NumRanges, Args); + } + +-ScopedReport::ScopedReport(ReportOptions Opts) : Opts(Opts) { ++ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc) ++ : Opts(Opts), SummaryLoc(SummaryLoc) { + InitIfNecessary(); + CommonSanitizerReportMutex.Lock(); + } + + ScopedReport::~ScopedReport() { + MaybePrintStackTrace(Opts.pc, Opts.bp); ++ MaybeReportErrorSummary(SummaryLoc); + CommonSanitizerReportMutex.Unlock(); + if (Opts.DieAfterReport || flags()->halt_on_error) + Die(); +Index: lib/ubsan/ubsan_diag.h +=================================================================== +--- lib/ubsan/ubsan_diag.h (revision 218129) ++++ lib/ubsan/ubsan_diag.h (working copy) +@@ -223,9 +223,10 @@ + /// different sanitizers won't be mixed. + class ScopedReport { + ReportOptions Opts; ++ Location SummaryLoc; + + public: +- ScopedReport(ReportOptions Opts); ++ ScopedReport(ReportOptions Opts, Location SummaryLoc); + ~ScopedReport(); + }; + +Index: test/ubsan/lit.common.cfg +=================================================================== +--- test/ubsan/lit.common.cfg (revision 218129) ++++ test/ubsan/lit.common.cfg (working copy) +@@ -18,9 +18,11 @@ + ubsan_lit_test_mode = get_required_attr(config, 'ubsan_lit_test_mode') + if ubsan_lit_test_mode == "Standalone": + config.name = 'UndefinedBehaviorSanitizer-Standalone' ++ config.available_features.add("ubsan-standalone") + clang_ubsan_cflags = [] + elif ubsan_lit_test_mode == "AddressSanitizer": + config.name = 'UndefinedBehaviorSanitizer-AddressSanitizer' ++ config.available_features.add("ubsan-asan") + clang_ubsan_cflags = ["-fsanitize=address"] + config.environment['ASAN_OPTIONS'] = 'detect_leaks=0' + else: +Index: test/ubsan/TestCases/Integer/summary.cpp +=================================================================== +--- test/ubsan/TestCases/Integer/summary.cpp (revision 0) ++++ test/ubsan/TestCases/Integer/summary.cpp (revision 0) +@@ -0,0 +1,10 @@ ++// RUN: %clangxx -fsanitize=integer %s -o %t && %t 2>&1 | FileCheck %s ++// REQUIRES: ubsan-asan ++ ++#include ++ ++int main() { ++ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull)); ++ // CHECK: SUMMARY: AddressSanitizer: runtime-error {{.*}}summary.cpp:[[@LINE-1]] ++ return 0; ++} Index: zdiff.zflags =================================================================== --- /dev/null +++ zdiff.zflags @@ -0,0 +1,65 @@ +Index: lib/ubsan/ubsan_init.cc +=================================================================== +--- lib/ubsan/ubsan_init.cc (revision 217616) ++++ lib/ubsan/ubsan_init.cc (working copy) +@@ -31,11 +31,12 @@ + #endif + if (LIKELY(ubsan_inited)) + return; +- if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) { +- // This will be overwritten if another sanitizer will initialize later. ++ bool standalone = (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")); ++ // Attention: if standalone is true, it means that some other sanitizer ++ // may still initialize later. ++ if (standalone) + SanitizerToolName = "UndefinedBehaviorSanitizer"; +- } +- InitializeFlags(); ++ InitializeFlags(standalone); + SuppressionContext::InitIfNecessary(); + ubsan_inited = true; + } +Index: lib/ubsan/ubsan_flags.cc +=================================================================== +--- lib/ubsan/ubsan_flags.cc (revision 217616) ++++ lib/ubsan/ubsan_flags.cc (working copy) +@@ -28,10 +28,12 @@ + #endif + } + +-static void InitializeCommonFlags() { ++static void InitializeCommonFlags(bool standalone) { + CommonFlags *cf = common_flags(); +- SetCommonFlagsDefaults(cf); +- cf->print_summary = false; ++ if (standalone) { ++ SetCommonFlagsDefaults(cf); ++ cf->print_summary = false; ++ } + // Override from compile definition. + ParseCommonFlagsFromString(cf, GetRuntimeFlagsFromCompileDefinition()); + // Override from environment variable. +@@ -49,8 +51,8 @@ + "Include full stacktrace into an error report"); + } + +-void InitializeFlags() { +- InitializeCommonFlags(); ++void InitializeFlags(bool standalone) { ++ InitializeCommonFlags(standalone); + Flags *f = flags(); + // Default values. + f->halt_on_error = false; +Index: lib/ubsan/ubsan_flags.h +=================================================================== +--- lib/ubsan/ubsan_flags.h (revision 217616) ++++ lib/ubsan/ubsan_flags.h (working copy) +@@ -23,7 +23,7 @@ + extern Flags ubsan_flags; + inline Flags *flags() { return &ubsan_flags; } + +-void InitializeFlags(); ++void InitializeFlags(bool standalone); + + } // namespace __ubsan +