146ba9697SNico Weber //===-- ubsan_diag.cpp ----------------------------------------------------===// 246ba9697SNico Weber // 346ba9697SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 446ba9697SNico Weber // See https://llvm.org/LICENSE.txt for license information. 546ba9697SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 646ba9697SNico Weber // 746ba9697SNico Weber //===----------------------------------------------------------------------===// 846ba9697SNico Weber // 946ba9697SNico Weber // Diagnostic reporting for the UBSan runtime. 1046ba9697SNico Weber // 1146ba9697SNico Weber //===----------------------------------------------------------------------===// 1246ba9697SNico Weber 1346ba9697SNico Weber #include "ubsan_platform.h" 1446ba9697SNico Weber #if CAN_SANITIZE_UB 1546ba9697SNico Weber #include "ubsan_diag.h" 1646ba9697SNico Weber #include "ubsan_init.h" 1746ba9697SNico Weber #include "ubsan_flags.h" 1846ba9697SNico Weber #include "ubsan_monitor.h" 1946ba9697SNico Weber #include "sanitizer_common/sanitizer_placement_new.h" 2046ba9697SNico Weber #include "sanitizer_common/sanitizer_report_decorator.h" 2146ba9697SNico Weber #include "sanitizer_common/sanitizer_stacktrace.h" 2246ba9697SNico Weber #include "sanitizer_common/sanitizer_stacktrace_printer.h" 2346ba9697SNico Weber #include "sanitizer_common/sanitizer_suppressions.h" 2446ba9697SNico Weber #include "sanitizer_common/sanitizer_symbolizer.h" 2546ba9697SNico Weber #include <stdio.h> 2646ba9697SNico Weber 2746ba9697SNico Weber using namespace __ubsan; 2846ba9697SNico Weber 2946ba9697SNico Weber // UBSan is combined with runtimes that already provide this functionality 3046ba9697SNico Weber // (e.g., ASan) as well as runtimes that lack it (e.g., scudo). Tried to use 3146ba9697SNico Weber // weak linkage to resolve this issue which is not portable and breaks on 3246ba9697SNico Weber // Windows. 3346ba9697SNico Weber // TODO(yln): This is a temporary workaround. GetStackTrace functions will be 3446ba9697SNico Weber // removed in the future. 3569fcf6a7SNikita Popov void ubsan_GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, 3669fcf6a7SNikita Popov uptr bp, void *context, bool request_fast) { 3769fcf6a7SNikita Popov uptr top = 0; 3869fcf6a7SNikita Popov uptr bottom = 0; 3969fcf6a7SNikita Popov GetThreadStackTopAndBottom(false, &top, &bottom); 4069fcf6a7SNikita Popov bool fast = StackTrace::WillUseFastUnwind(request_fast); 4169fcf6a7SNikita Popov stack->Unwind(max_depth, pc, bp, context, top, bottom, fast); 4246ba9697SNico Weber } 4346ba9697SNico Weber 4446ba9697SNico Weber static void MaybePrintStackTrace(uptr pc, uptr bp) { 4546ba9697SNico Weber // We assume that flags are already parsed, as UBSan runtime 4646ba9697SNico Weber // will definitely be called when we print the first diagnostics message. 4746ba9697SNico Weber if (!flags()->print_stacktrace) 4846ba9697SNico Weber return; 4946ba9697SNico Weber 50*aacd1afaSFlorian Mayer UNINITIALIZED BufferedStackTrace stack; 5169fcf6a7SNikita Popov ubsan_GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, 5246ba9697SNico Weber common_flags()->fast_unwind_on_fatal); 5346ba9697SNico Weber stack.Print(); 5446ba9697SNico Weber } 5546ba9697SNico Weber 5646ba9697SNico Weber static const char *ConvertTypeToString(ErrorType Type) { 5746ba9697SNico Weber switch (Type) { 5846ba9697SNico Weber #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \ 5946ba9697SNico Weber case ErrorType::Name: \ 6046ba9697SNico Weber return SummaryKind; 6146ba9697SNico Weber #include "ubsan_checks.inc" 6246ba9697SNico Weber #undef UBSAN_CHECK 6346ba9697SNico Weber } 6446ba9697SNico Weber UNREACHABLE("unknown ErrorType!"); 6546ba9697SNico Weber } 6646ba9697SNico Weber 6746ba9697SNico Weber static const char *ConvertTypeToFlagName(ErrorType Type) { 6846ba9697SNico Weber switch (Type) { 6946ba9697SNico Weber #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \ 7046ba9697SNico Weber case ErrorType::Name: \ 7146ba9697SNico Weber return FSanitizeFlagName; 7246ba9697SNico Weber #include "ubsan_checks.inc" 7346ba9697SNico Weber #undef UBSAN_CHECK 7446ba9697SNico Weber } 7546ba9697SNico Weber UNREACHABLE("unknown ErrorType!"); 7646ba9697SNico Weber } 7746ba9697SNico Weber 7846ba9697SNico Weber static void MaybeReportErrorSummary(Location Loc, ErrorType Type) { 7946ba9697SNico Weber if (!common_flags()->print_summary) 8046ba9697SNico Weber return; 8146ba9697SNico Weber if (!flags()->report_error_type) 8246ba9697SNico Weber Type = ErrorType::GenericUB; 8346ba9697SNico Weber const char *ErrorKind = ConvertTypeToString(Type); 8446ba9697SNico Weber if (Loc.isSourceLocation()) { 8546ba9697SNico Weber SourceLocation SLoc = Loc.getSourceLocation(); 8646ba9697SNico Weber if (!SLoc.isInvalid()) { 8746ba9697SNico Weber AddressInfo AI; 8846ba9697SNico Weber AI.file = internal_strdup(SLoc.getFilename()); 8946ba9697SNico Weber AI.line = SLoc.getLine(); 9046ba9697SNico Weber AI.column = SLoc.getColumn(); 9109e0d71aSVitaly Buka AI.function = nullptr; 9246ba9697SNico Weber ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); 9346ba9697SNico Weber AI.Clear(); 9446ba9697SNico Weber return; 9546ba9697SNico Weber } 9646ba9697SNico Weber } else if (Loc.isSymbolizedStack()) { 9746ba9697SNico Weber const AddressInfo &AI = Loc.getSymbolizedStack()->info; 9846ba9697SNico Weber ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); 9946ba9697SNico Weber return; 10046ba9697SNico Weber } 10146ba9697SNico Weber ReportErrorSummary(ErrorKind, GetSanititizerToolName()); 10246ba9697SNico Weber } 10346ba9697SNico Weber 10446ba9697SNico Weber namespace { 10546ba9697SNico Weber class Decorator : public SanitizerCommonDecorator { 10646ba9697SNico Weber public: 10746ba9697SNico Weber Decorator() : SanitizerCommonDecorator() {} 10846ba9697SNico Weber const char *Highlight() const { return Green(); } 10946ba9697SNico Weber const char *Note() const { return Black(); } 11046ba9697SNico Weber }; 11146ba9697SNico Weber } 11246ba9697SNico Weber 11346ba9697SNico Weber SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) { 11446ba9697SNico Weber InitAsStandaloneIfNecessary(); 11546ba9697SNico Weber return Symbolizer::GetOrInit()->SymbolizePC(PC); 11646ba9697SNico Weber } 11746ba9697SNico Weber 11846ba9697SNico Weber Diag &Diag::operator<<(const TypeDescriptor &V) { 11946ba9697SNico Weber return AddArg(V.getTypeName()); 12046ba9697SNico Weber } 12146ba9697SNico Weber 12246ba9697SNico Weber Diag &Diag::operator<<(const Value &V) { 12346ba9697SNico Weber if (V.getType().isSignedIntegerTy()) 12446ba9697SNico Weber AddArg(V.getSIntValue()); 12546ba9697SNico Weber else if (V.getType().isUnsignedIntegerTy()) 12646ba9697SNico Weber AddArg(V.getUIntValue()); 12746ba9697SNico Weber else if (V.getType().isFloatTy()) 12846ba9697SNico Weber AddArg(V.getFloatValue()); 12946ba9697SNico Weber else 13046ba9697SNico Weber AddArg("<unknown>"); 13146ba9697SNico Weber return *this; 13246ba9697SNico Weber } 13346ba9697SNico Weber 13446ba9697SNico Weber /// Hexadecimal printing for numbers too large for Printf to handle directly. 13546ba9697SNico Weber static void RenderHex(InternalScopedString *Buffer, UIntMax Val) { 13646ba9697SNico Weber #if HAVE_INT128_T 1375b7dfa96SVitaly Buka Buffer->AppendF("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96), 13846ba9697SNico Weber (unsigned int)(Val >> 64), (unsigned int)(Val >> 32), 13946ba9697SNico Weber (unsigned int)(Val)); 14046ba9697SNico Weber #else 14146ba9697SNico Weber UNREACHABLE("long long smaller than 64 bits?"); 14246ba9697SNico Weber #endif 14346ba9697SNico Weber } 14446ba9697SNico Weber 14546ba9697SNico Weber static void RenderLocation(InternalScopedString *Buffer, Location Loc) { 14646ba9697SNico Weber switch (Loc.getKind()) { 14746ba9697SNico Weber case Location::LK_Source: { 14846ba9697SNico Weber SourceLocation SLoc = Loc.getSourceLocation(); 14946ba9697SNico Weber if (SLoc.isInvalid()) 1505b7dfa96SVitaly Buka Buffer->AppendF("<unknown>"); 15146ba9697SNico Weber else 152f8ae2e42SAndres Villegas StackTracePrinter::GetOrInit()->RenderSourceLocation( 153f8ae2e42SAndres Villegas Buffer, SLoc.getFilename(), SLoc.getLine(), SLoc.getColumn(), 154f8ae2e42SAndres Villegas common_flags()->symbolize_vs_style, 15546ba9697SNico Weber common_flags()->strip_path_prefix); 15646ba9697SNico Weber return; 15746ba9697SNico Weber } 15846ba9697SNico Weber case Location::LK_Memory: 1595b7dfa96SVitaly Buka Buffer->AppendF("%p", reinterpret_cast<void *>(Loc.getMemoryLocation())); 16046ba9697SNico Weber return; 16146ba9697SNico Weber case Location::LK_Symbolized: { 16246ba9697SNico Weber const AddressInfo &Info = Loc.getSymbolizedStack()->info; 16346ba9697SNico Weber if (Info.file) 164f8ae2e42SAndres Villegas StackTracePrinter::GetOrInit()->RenderSourceLocation( 165f8ae2e42SAndres Villegas Buffer, Info.file, Info.line, Info.column, 16646ba9697SNico Weber common_flags()->symbolize_vs_style, 16746ba9697SNico Weber common_flags()->strip_path_prefix); 16846ba9697SNico Weber else if (Info.module) 169f8ae2e42SAndres Villegas StackTracePrinter::GetOrInit()->RenderModuleLocation( 170f8ae2e42SAndres Villegas Buffer, Info.module, Info.module_offset, Info.module_arch, 171f8ae2e42SAndres Villegas common_flags()->strip_path_prefix); 17246ba9697SNico Weber else 1735b7dfa96SVitaly Buka Buffer->AppendF("%p", reinterpret_cast<void *>(Info.address)); 17446ba9697SNico Weber return; 17546ba9697SNico Weber } 17646ba9697SNico Weber case Location::LK_Null: 1775b7dfa96SVitaly Buka Buffer->AppendF("<unknown>"); 17846ba9697SNico Weber return; 17946ba9697SNico Weber } 18046ba9697SNico Weber } 18146ba9697SNico Weber 18246ba9697SNico Weber static void RenderText(InternalScopedString *Buffer, const char *Message, 18346ba9697SNico Weber const Diag::Arg *Args) { 18446ba9697SNico Weber for (const char *Msg = Message; *Msg; ++Msg) { 18546ba9697SNico Weber if (*Msg != '%') { 1865b7dfa96SVitaly Buka Buffer->AppendF("%c", *Msg); 18746ba9697SNico Weber continue; 18846ba9697SNico Weber } 18946ba9697SNico Weber const Diag::Arg &A = Args[*++Msg - '0']; 19046ba9697SNico Weber switch (A.Kind) { 19146ba9697SNico Weber case Diag::AK_String: 1925b7dfa96SVitaly Buka Buffer->AppendF("%s", A.String); 19346ba9697SNico Weber break; 19446ba9697SNico Weber case Diag::AK_TypeName: { 19546ba9697SNico Weber if (SANITIZER_WINDOWS) 19646ba9697SNico Weber // The Windows implementation demangles names early. 1975b7dfa96SVitaly Buka Buffer->AppendF("'%s'", A.String); 19846ba9697SNico Weber else 1995b7dfa96SVitaly Buka Buffer->AppendF("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); 20046ba9697SNico Weber break; 20146ba9697SNico Weber } 20246ba9697SNico Weber case Diag::AK_SInt: 20346ba9697SNico Weber // 'long long' is guaranteed to be at least 64 bits wide. 20446ba9697SNico Weber if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX) 2055b7dfa96SVitaly Buka Buffer->AppendF("%lld", (long long)A.SInt); 20646ba9697SNico Weber else 20746ba9697SNico Weber RenderHex(Buffer, A.SInt); 20846ba9697SNico Weber break; 20946ba9697SNico Weber case Diag::AK_UInt: 21046ba9697SNico Weber if (A.UInt <= UINT64_MAX) 2115b7dfa96SVitaly Buka Buffer->AppendF("%llu", (unsigned long long)A.UInt); 21246ba9697SNico Weber else 21346ba9697SNico Weber RenderHex(Buffer, A.UInt); 21446ba9697SNico Weber break; 21546ba9697SNico Weber case Diag::AK_Float: { 21646ba9697SNico Weber // FIXME: Support floating-point formatting in sanitizer_common's 21746ba9697SNico Weber // printf, and stop using snprintf here. 21846ba9697SNico Weber char FloatBuffer[32]; 21946ba9697SNico Weber #if SANITIZER_WINDOWS 220fb012c1eSMartin Storsjö // On MSVC platforms, long doubles are equal to regular doubles. 221fb012c1eSMartin Storsjö // In MinGW environments on x86, long doubles are 80 bit, but here, 222fb012c1eSMartin Storsjö // we're calling an MS CRT provided printf function which considers 223fb012c1eSMartin Storsjö // long doubles to be 64 bit. Just cast the float value to a regular 224fb012c1eSMartin Storsjö // double to avoid the potential ambiguity in MinGW mode. 225fb012c1eSMartin Storsjö sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%g", (double)A.Float); 22646ba9697SNico Weber #else 22746ba9697SNico Weber snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float); 22846ba9697SNico Weber #endif 2294a374876SVitaly Buka Buffer->Append(FloatBuffer); 23046ba9697SNico Weber break; 23146ba9697SNico Weber } 23246ba9697SNico Weber case Diag::AK_Pointer: 2335b7dfa96SVitaly Buka Buffer->AppendF("%p", A.Pointer); 23446ba9697SNico Weber break; 23546ba9697SNico Weber } 23646ba9697SNico Weber } 23746ba9697SNico Weber } 23846ba9697SNico Weber 23946ba9697SNico Weber /// Find the earliest-starting range in Ranges which ends after Loc. 24046ba9697SNico Weber static Range *upperBound(MemoryLocation Loc, Range *Ranges, 24146ba9697SNico Weber unsigned NumRanges) { 24246ba9697SNico Weber Range *Best = 0; 24346ba9697SNico Weber for (unsigned I = 0; I != NumRanges; ++I) 24446ba9697SNico Weber if (Ranges[I].getEnd().getMemoryLocation() > Loc && 24546ba9697SNico Weber (!Best || 24646ba9697SNico Weber Best->getStart().getMemoryLocation() > 24746ba9697SNico Weber Ranges[I].getStart().getMemoryLocation())) 24846ba9697SNico Weber Best = &Ranges[I]; 24946ba9697SNico Weber return Best; 25046ba9697SNico Weber } 25146ba9697SNico Weber 25246ba9697SNico Weber static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) { 25346ba9697SNico Weber return (LHS < RHS) ? 0 : LHS - RHS; 25446ba9697SNico Weber } 25546ba9697SNico Weber 25646ba9697SNico Weber static inline uptr addNoOverflow(uptr LHS, uptr RHS) { 25746ba9697SNico Weber const uptr Limit = (uptr)-1; 25846ba9697SNico Weber return (LHS > Limit - RHS) ? Limit : LHS + RHS; 25946ba9697SNico Weber } 26046ba9697SNico Weber 26146ba9697SNico Weber /// Render a snippet of the address space near a location. 26246ba9697SNico Weber static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc, 26346ba9697SNico Weber Range *Ranges, unsigned NumRanges, 26446ba9697SNico Weber const Diag::Arg *Args) { 26546ba9697SNico Weber // Show at least the 8 bytes surrounding Loc. 26646ba9697SNico Weber const unsigned MinBytesNearLoc = 4; 26746ba9697SNico Weber MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc); 26846ba9697SNico Weber MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc); 26946ba9697SNico Weber MemoryLocation OrigMin = Min; 27046ba9697SNico Weber for (unsigned I = 0; I < NumRanges; ++I) { 27146ba9697SNico Weber Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); 27246ba9697SNico Weber Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); 27346ba9697SNico Weber } 27446ba9697SNico Weber 27546ba9697SNico Weber // If we have too many interesting bytes, prefer to show bytes after Loc. 27646ba9697SNico Weber const unsigned BytesToShow = 32; 27746ba9697SNico Weber if (Max - Min > BytesToShow) 27846ba9697SNico Weber Min = __sanitizer::Min(Max - BytesToShow, OrigMin); 27946ba9697SNico Weber Max = addNoOverflow(Min, BytesToShow); 28046ba9697SNico Weber 28146ba9697SNico Weber if (!IsAccessibleMemoryRange(Min, Max - Min)) { 28246ba9697SNico Weber Printf("<memory cannot be printed>\n"); 28346ba9697SNico Weber return; 28446ba9697SNico Weber } 28546ba9697SNico Weber 28646ba9697SNico Weber // Emit data. 287e0dadf3dSVitaly Buka InternalScopedString Buffer; 28846ba9697SNico Weber for (uptr P = Min; P != Max; ++P) { 28946ba9697SNico Weber unsigned char C = *reinterpret_cast<const unsigned char*>(P); 2905b7dfa96SVitaly Buka Buffer.AppendF("%s%02x", (P % 8 == 0) ? " " : " ", C); 29146ba9697SNico Weber } 2925b7dfa96SVitaly Buka Buffer.AppendF("\n"); 29346ba9697SNico Weber 29446ba9697SNico Weber // Emit highlights. 2954a374876SVitaly Buka Buffer.Append(Decor.Highlight()); 29646ba9697SNico Weber Range *InRange = upperBound(Min, Ranges, NumRanges); 29746ba9697SNico Weber for (uptr P = Min; P != Max; ++P) { 29846ba9697SNico Weber char Pad = ' ', Byte = ' '; 29946ba9697SNico Weber if (InRange && InRange->getEnd().getMemoryLocation() == P) 30046ba9697SNico Weber InRange = upperBound(P, Ranges, NumRanges); 30146ba9697SNico Weber if (!InRange && P > Loc) 30246ba9697SNico Weber break; 30346ba9697SNico Weber if (InRange && InRange->getStart().getMemoryLocation() < P) 30446ba9697SNico Weber Pad = '~'; 30546ba9697SNico Weber if (InRange && InRange->getStart().getMemoryLocation() <= P) 30646ba9697SNico Weber Byte = '~'; 30746ba9697SNico Weber if (P % 8 == 0) 3085b7dfa96SVitaly Buka Buffer.AppendF("%c", Pad); 3095b7dfa96SVitaly Buka Buffer.AppendF("%c", Pad); 3105b7dfa96SVitaly Buka Buffer.AppendF("%c", P == Loc ? '^' : Byte); 3115b7dfa96SVitaly Buka Buffer.AppendF("%c", Byte); 31246ba9697SNico Weber } 3135b7dfa96SVitaly Buka Buffer.AppendF("%s\n", Decor.Default()); 31446ba9697SNico Weber 31546ba9697SNico Weber // Go over the line again, and print names for the ranges. 31646ba9697SNico Weber InRange = 0; 31746ba9697SNico Weber unsigned Spaces = 0; 31846ba9697SNico Weber for (uptr P = Min; P != Max; ++P) { 31946ba9697SNico Weber if (!InRange || InRange->getEnd().getMemoryLocation() == P) 32046ba9697SNico Weber InRange = upperBound(P, Ranges, NumRanges); 32146ba9697SNico Weber if (!InRange) 32246ba9697SNico Weber break; 32346ba9697SNico Weber 32446ba9697SNico Weber Spaces += (P % 8) == 0 ? 2 : 1; 32546ba9697SNico Weber 32646ba9697SNico Weber if (InRange && InRange->getStart().getMemoryLocation() == P) { 32746ba9697SNico Weber while (Spaces--) 3285b7dfa96SVitaly Buka Buffer.AppendF(" "); 32946ba9697SNico Weber RenderText(&Buffer, InRange->getText(), Args); 3305b7dfa96SVitaly Buka Buffer.AppendF("\n"); 33146ba9697SNico Weber // FIXME: We only support naming one range for now! 33246ba9697SNico Weber break; 33346ba9697SNico Weber } 33446ba9697SNico Weber 33546ba9697SNico Weber Spaces += 2; 33646ba9697SNico Weber } 33746ba9697SNico Weber 33846ba9697SNico Weber Printf("%s", Buffer.data()); 33946ba9697SNico Weber // FIXME: Print names for anything we can identify within the line: 34046ba9697SNico Weber // 34146ba9697SNico Weber // * If we can identify the memory itself as belonging to a particular 34246ba9697SNico Weber // global, stack variable, or dynamic allocation, then do so. 34346ba9697SNico Weber // 34446ba9697SNico Weber // * If we have a pointer-size, pointer-aligned range highlighted, 34546ba9697SNico Weber // determine whether the value of that range is a pointer to an 34646ba9697SNico Weber // entity which we can name, and if so, print that name. 34746ba9697SNico Weber // 34846ba9697SNico Weber // This needs an external symbolizer, or (preferably) ASan instrumentation. 34946ba9697SNico Weber } 35046ba9697SNico Weber 35146ba9697SNico Weber Diag::~Diag() { 35246ba9697SNico Weber // All diagnostics should be printed under report mutex. 35346ba9697SNico Weber ScopedReport::CheckLocked(); 35446ba9697SNico Weber Decorator Decor; 355e0dadf3dSVitaly Buka InternalScopedString Buffer; 35646ba9697SNico Weber 35746ba9697SNico Weber // Prepare a report that a monitor process can inspect. 35846ba9697SNico Weber if (Level == DL_Error) { 35946ba9697SNico Weber RenderText(&Buffer, Message, Args); 36046ba9697SNico Weber UndefinedBehaviorReport UBR{ConvertTypeToString(ET), Loc, Buffer}; 36146ba9697SNico Weber Buffer.clear(); 36246ba9697SNico Weber } 36346ba9697SNico Weber 3644a374876SVitaly Buka Buffer.Append(Decor.Bold()); 36546ba9697SNico Weber RenderLocation(&Buffer, Loc); 3665b7dfa96SVitaly Buka Buffer.AppendF(":"); 36746ba9697SNico Weber 36846ba9697SNico Weber switch (Level) { 36946ba9697SNico Weber case DL_Error: 3705b7dfa96SVitaly Buka Buffer.AppendF("%s runtime error: %s%s", Decor.Warning(), Decor.Default(), 37146ba9697SNico Weber Decor.Bold()); 37246ba9697SNico Weber break; 37346ba9697SNico Weber 37446ba9697SNico Weber case DL_Note: 3755b7dfa96SVitaly Buka Buffer.AppendF("%s note: %s", Decor.Note(), Decor.Default()); 37646ba9697SNico Weber break; 37746ba9697SNico Weber } 37846ba9697SNico Weber 37946ba9697SNico Weber RenderText(&Buffer, Message, Args); 38046ba9697SNico Weber 3815b7dfa96SVitaly Buka Buffer.AppendF("%s\n", Decor.Default()); 38246ba9697SNico Weber Printf("%s", Buffer.data()); 38346ba9697SNico Weber 38446ba9697SNico Weber if (Loc.isMemoryLocation()) 38546ba9697SNico Weber PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args); 38646ba9697SNico Weber } 38746ba9697SNico Weber 38846ba9697SNico Weber ScopedReport::Initializer::Initializer() { InitAsStandaloneIfNecessary(); } 38946ba9697SNico Weber 39046ba9697SNico Weber ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc, 39146ba9697SNico Weber ErrorType Type) 39246ba9697SNico Weber : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {} 39346ba9697SNico Weber 39446ba9697SNico Weber ScopedReport::~ScopedReport() { 39546ba9697SNico Weber MaybePrintStackTrace(Opts.pc, Opts.bp); 39646ba9697SNico Weber MaybeReportErrorSummary(SummaryLoc, Type); 3979059903fSEmily Shi 3989059903fSEmily Shi if (common_flags()->print_module_map >= 2) 3999059903fSEmily Shi DumpProcessMap(); 4009059903fSEmily Shi 40146ba9697SNico Weber if (flags()->halt_on_error) 40246ba9697SNico Weber Die(); 40346ba9697SNico Weber } 40446ba9697SNico Weber 405ba66d60bSFangrui Song alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)]; 40646ba9697SNico Weber static SuppressionContext *suppression_ctx = nullptr; 40746ba9697SNico Weber static const char kVptrCheck[] = "vptr_check"; 40846ba9697SNico Weber static const char *kSuppressionTypes[] = { 40946ba9697SNico Weber #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName, 41046ba9697SNico Weber #include "ubsan_checks.inc" 41146ba9697SNico Weber #undef UBSAN_CHECK 41246ba9697SNico Weber kVptrCheck, 41346ba9697SNico Weber }; 41446ba9697SNico Weber 41546ba9697SNico Weber void __ubsan::InitializeSuppressions() { 41646ba9697SNico Weber CHECK_EQ(nullptr, suppression_ctx); 417c0fa6322SVitaly Buka suppression_ctx = new (suppression_placeholder) 41846ba9697SNico Weber SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); 41946ba9697SNico Weber suppression_ctx->ParseFromFile(flags()->suppressions); 42046ba9697SNico Weber } 42146ba9697SNico Weber 42246ba9697SNico Weber bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) { 42346ba9697SNico Weber InitAsStandaloneIfNecessary(); 42446ba9697SNico Weber CHECK(suppression_ctx); 42546ba9697SNico Weber Suppression *s; 42646ba9697SNico Weber return suppression_ctx->Match(TypeName, kVptrCheck, &s); 42746ba9697SNico Weber } 42846ba9697SNico Weber 42946ba9697SNico Weber bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) { 43046ba9697SNico Weber InitAsStandaloneIfNecessary(); 43146ba9697SNico Weber CHECK(suppression_ctx); 43246ba9697SNico Weber const char *SuppType = ConvertTypeToFlagName(ET); 43346ba9697SNico Weber // Fast path: don't symbolize PC if there is no suppressions for given UB 43446ba9697SNico Weber // type. 43546ba9697SNico Weber if (!suppression_ctx->HasSuppressionType(SuppType)) 43646ba9697SNico Weber return false; 43746ba9697SNico Weber Suppression *s = nullptr; 43846ba9697SNico Weber // Suppress by file name known to runtime. 43946ba9697SNico Weber if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s)) 44046ba9697SNico Weber return true; 44146ba9697SNico Weber // Suppress by module name. 44246ba9697SNico Weber if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) { 44346ba9697SNico Weber if (suppression_ctx->Match(Module, SuppType, &s)) 44446ba9697SNico Weber return true; 44546ba9697SNico Weber } 44646ba9697SNico Weber // Suppress by function or source file name from debug info. 44746ba9697SNico Weber SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC)); 44846ba9697SNico Weber const AddressInfo &AI = Stack.get()->info; 44946ba9697SNico Weber return suppression_ctx->Match(AI.function, SuppType, &s) || 45046ba9697SNico Weber suppression_ctx->Match(AI.file, SuppType, &s); 45146ba9697SNico Weber } 45246ba9697SNico Weber 45346ba9697SNico Weber #endif // CAN_SANITIZE_UB 454