168d75effSDimitry Andric //===-- ubsan_diag.cpp ----------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // Diagnostic reporting for the UBSan runtime. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 1368d75effSDimitry Andric #include "ubsan_platform.h" 1468d75effSDimitry Andric #if CAN_SANITIZE_UB 1568d75effSDimitry Andric #include "ubsan_diag.h" 1668d75effSDimitry Andric #include "ubsan_init.h" 1768d75effSDimitry Andric #include "ubsan_flags.h" 1868d75effSDimitry Andric #include "ubsan_monitor.h" 1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 2068d75effSDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h" 2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h" 2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace_printer.h" 2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_suppressions.h" 2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h" 2568d75effSDimitry Andric #include <stdio.h> 2668d75effSDimitry Andric 2768d75effSDimitry Andric using namespace __ubsan; 2868d75effSDimitry Andric 2968d75effSDimitry Andric // UBSan is combined with runtimes that already provide this functionality 3068d75effSDimitry Andric // (e.g., ASan) as well as runtimes that lack it (e.g., scudo). Tried to use 3168d75effSDimitry Andric // weak linkage to resolve this issue which is not portable and breaks on 3268d75effSDimitry Andric // Windows. 3368d75effSDimitry Andric // TODO(yln): This is a temporary workaround. GetStackTrace functions will be 3468d75effSDimitry Andric // removed in the future. 3581ad6265SDimitry Andric void ubsan_GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, 3681ad6265SDimitry Andric uptr bp, void *context, bool request_fast) { 3768d75effSDimitry Andric uptr top = 0; 3868d75effSDimitry Andric uptr bottom = 0; 3968d75effSDimitry Andric GetThreadStackTopAndBottom(false, &top, &bottom); 4081ad6265SDimitry Andric bool fast = StackTrace::WillUseFastUnwind(request_fast); 4181ad6265SDimitry Andric stack->Unwind(max_depth, pc, bp, context, top, bottom, fast); 4268d75effSDimitry Andric } 4368d75effSDimitry Andric 4468d75effSDimitry Andric static void MaybePrintStackTrace(uptr pc, uptr bp) { 4568d75effSDimitry Andric // We assume that flags are already parsed, as UBSan runtime 4668d75effSDimitry Andric // will definitely be called when we print the first diagnostics message. 4768d75effSDimitry Andric if (!flags()->print_stacktrace) 4868d75effSDimitry Andric return; 4968d75effSDimitry Andric 5068d75effSDimitry Andric BufferedStackTrace stack; 5168d75effSDimitry Andric ubsan_GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, 5268d75effSDimitry Andric common_flags()->fast_unwind_on_fatal); 5368d75effSDimitry Andric stack.Print(); 5468d75effSDimitry Andric } 5568d75effSDimitry Andric 5668d75effSDimitry Andric static const char *ConvertTypeToString(ErrorType Type) { 5768d75effSDimitry Andric switch (Type) { 5868d75effSDimitry Andric #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \ 5968d75effSDimitry Andric case ErrorType::Name: \ 6068d75effSDimitry Andric return SummaryKind; 6168d75effSDimitry Andric #include "ubsan_checks.inc" 6268d75effSDimitry Andric #undef UBSAN_CHECK 6368d75effSDimitry Andric } 6468d75effSDimitry Andric UNREACHABLE("unknown ErrorType!"); 6568d75effSDimitry Andric } 6668d75effSDimitry Andric 6768d75effSDimitry Andric static const char *ConvertTypeToFlagName(ErrorType Type) { 6868d75effSDimitry Andric switch (Type) { 6968d75effSDimitry Andric #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \ 7068d75effSDimitry Andric case ErrorType::Name: \ 7168d75effSDimitry Andric return FSanitizeFlagName; 7268d75effSDimitry Andric #include "ubsan_checks.inc" 7368d75effSDimitry Andric #undef UBSAN_CHECK 7468d75effSDimitry Andric } 7568d75effSDimitry Andric UNREACHABLE("unknown ErrorType!"); 7668d75effSDimitry Andric } 7768d75effSDimitry Andric 7868d75effSDimitry Andric static void MaybeReportErrorSummary(Location Loc, ErrorType Type) { 7968d75effSDimitry Andric if (!common_flags()->print_summary) 8068d75effSDimitry Andric return; 8168d75effSDimitry Andric if (!flags()->report_error_type) 8268d75effSDimitry Andric Type = ErrorType::GenericUB; 8368d75effSDimitry Andric const char *ErrorKind = ConvertTypeToString(Type); 8468d75effSDimitry Andric if (Loc.isSourceLocation()) { 8568d75effSDimitry Andric SourceLocation SLoc = Loc.getSourceLocation(); 8668d75effSDimitry Andric if (!SLoc.isInvalid()) { 8768d75effSDimitry Andric AddressInfo AI; 8868d75effSDimitry Andric AI.file = internal_strdup(SLoc.getFilename()); 8968d75effSDimitry Andric AI.line = SLoc.getLine(); 9068d75effSDimitry Andric AI.column = SLoc.getColumn(); 911db9f3b2SDimitry Andric AI.function = nullptr; 9268d75effSDimitry Andric ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); 9368d75effSDimitry Andric AI.Clear(); 9468d75effSDimitry Andric return; 9568d75effSDimitry Andric } 9668d75effSDimitry Andric } else if (Loc.isSymbolizedStack()) { 9768d75effSDimitry Andric const AddressInfo &AI = Loc.getSymbolizedStack()->info; 9868d75effSDimitry Andric ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); 9968d75effSDimitry Andric return; 10068d75effSDimitry Andric } 10168d75effSDimitry Andric ReportErrorSummary(ErrorKind, GetSanititizerToolName()); 10268d75effSDimitry Andric } 10368d75effSDimitry Andric 10468d75effSDimitry Andric namespace { 10568d75effSDimitry Andric class Decorator : public SanitizerCommonDecorator { 10668d75effSDimitry Andric public: 10768d75effSDimitry Andric Decorator() : SanitizerCommonDecorator() {} 10868d75effSDimitry Andric const char *Highlight() const { return Green(); } 10968d75effSDimitry Andric const char *Note() const { return Black(); } 11068d75effSDimitry Andric }; 11168d75effSDimitry Andric } 11268d75effSDimitry Andric 11368d75effSDimitry Andric SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) { 11468d75effSDimitry Andric InitAsStandaloneIfNecessary(); 11568d75effSDimitry Andric return Symbolizer::GetOrInit()->SymbolizePC(PC); 11668d75effSDimitry Andric } 11768d75effSDimitry Andric 11868d75effSDimitry Andric Diag &Diag::operator<<(const TypeDescriptor &V) { 11968d75effSDimitry Andric return AddArg(V.getTypeName()); 12068d75effSDimitry Andric } 12168d75effSDimitry Andric 12268d75effSDimitry Andric Diag &Diag::operator<<(const Value &V) { 12368d75effSDimitry Andric if (V.getType().isSignedIntegerTy()) 12468d75effSDimitry Andric AddArg(V.getSIntValue()); 12568d75effSDimitry Andric else if (V.getType().isUnsignedIntegerTy()) 12668d75effSDimitry Andric AddArg(V.getUIntValue()); 12768d75effSDimitry Andric else if (V.getType().isFloatTy()) 12868d75effSDimitry Andric AddArg(V.getFloatValue()); 12968d75effSDimitry Andric else 13068d75effSDimitry Andric AddArg("<unknown>"); 13168d75effSDimitry Andric return *this; 13268d75effSDimitry Andric } 13368d75effSDimitry Andric 13468d75effSDimitry Andric /// Hexadecimal printing for numbers too large for Printf to handle directly. 13568d75effSDimitry Andric static void RenderHex(InternalScopedString *Buffer, UIntMax Val) { 13668d75effSDimitry Andric #if HAVE_INT128_T 1375f757f3fSDimitry Andric Buffer->AppendF("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96), 13868d75effSDimitry Andric (unsigned int)(Val >> 64), (unsigned int)(Val >> 32), 13968d75effSDimitry Andric (unsigned int)(Val)); 14068d75effSDimitry Andric #else 14168d75effSDimitry Andric UNREACHABLE("long long smaller than 64 bits?"); 14268d75effSDimitry Andric #endif 14368d75effSDimitry Andric } 14468d75effSDimitry Andric 14568d75effSDimitry Andric static void RenderLocation(InternalScopedString *Buffer, Location Loc) { 14668d75effSDimitry Andric switch (Loc.getKind()) { 14768d75effSDimitry Andric case Location::LK_Source: { 14868d75effSDimitry Andric SourceLocation SLoc = Loc.getSourceLocation(); 14968d75effSDimitry Andric if (SLoc.isInvalid()) 1505f757f3fSDimitry Andric Buffer->AppendF("<unknown>"); 15168d75effSDimitry Andric else 1525f757f3fSDimitry Andric StackTracePrinter::GetOrInit()->RenderSourceLocation( 1535f757f3fSDimitry Andric Buffer, SLoc.getFilename(), SLoc.getLine(), SLoc.getColumn(), 1545f757f3fSDimitry Andric common_flags()->symbolize_vs_style, 15568d75effSDimitry Andric common_flags()->strip_path_prefix); 15668d75effSDimitry Andric return; 15768d75effSDimitry Andric } 15868d75effSDimitry Andric case Location::LK_Memory: 1595f757f3fSDimitry Andric Buffer->AppendF("%p", reinterpret_cast<void *>(Loc.getMemoryLocation())); 16068d75effSDimitry Andric return; 16168d75effSDimitry Andric case Location::LK_Symbolized: { 16268d75effSDimitry Andric const AddressInfo &Info = Loc.getSymbolizedStack()->info; 16368d75effSDimitry Andric if (Info.file) 1645f757f3fSDimitry Andric StackTracePrinter::GetOrInit()->RenderSourceLocation( 1655f757f3fSDimitry Andric Buffer, Info.file, Info.line, Info.column, 16668d75effSDimitry Andric common_flags()->symbolize_vs_style, 16768d75effSDimitry Andric common_flags()->strip_path_prefix); 16868d75effSDimitry Andric else if (Info.module) 1695f757f3fSDimitry Andric StackTracePrinter::GetOrInit()->RenderModuleLocation( 1705f757f3fSDimitry Andric Buffer, Info.module, Info.module_offset, Info.module_arch, 1715f757f3fSDimitry Andric common_flags()->strip_path_prefix); 17268d75effSDimitry Andric else 1735f757f3fSDimitry Andric Buffer->AppendF("%p", reinterpret_cast<void *>(Info.address)); 17468d75effSDimitry Andric return; 17568d75effSDimitry Andric } 17668d75effSDimitry Andric case Location::LK_Null: 1775f757f3fSDimitry Andric Buffer->AppendF("<unknown>"); 17868d75effSDimitry Andric return; 17968d75effSDimitry Andric } 18068d75effSDimitry Andric } 18168d75effSDimitry Andric 18268d75effSDimitry Andric static void RenderText(InternalScopedString *Buffer, const char *Message, 18368d75effSDimitry Andric const Diag::Arg *Args) { 18468d75effSDimitry Andric for (const char *Msg = Message; *Msg; ++Msg) { 18568d75effSDimitry Andric if (*Msg != '%') { 1865f757f3fSDimitry Andric Buffer->AppendF("%c", *Msg); 18768d75effSDimitry Andric continue; 18868d75effSDimitry Andric } 18968d75effSDimitry Andric const Diag::Arg &A = Args[*++Msg - '0']; 19068d75effSDimitry Andric switch (A.Kind) { 19168d75effSDimitry Andric case Diag::AK_String: 1925f757f3fSDimitry Andric Buffer->AppendF("%s", A.String); 19368d75effSDimitry Andric break; 19468d75effSDimitry Andric case Diag::AK_TypeName: { 19568d75effSDimitry Andric if (SANITIZER_WINDOWS) 19668d75effSDimitry Andric // The Windows implementation demangles names early. 1975f757f3fSDimitry Andric Buffer->AppendF("'%s'", A.String); 19868d75effSDimitry Andric else 1995f757f3fSDimitry Andric Buffer->AppendF("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); 20068d75effSDimitry Andric break; 20168d75effSDimitry Andric } 20268d75effSDimitry Andric case Diag::AK_SInt: 20368d75effSDimitry Andric // 'long long' is guaranteed to be at least 64 bits wide. 20468d75effSDimitry Andric if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX) 2055f757f3fSDimitry Andric Buffer->AppendF("%lld", (long long)A.SInt); 20668d75effSDimitry Andric else 20768d75effSDimitry Andric RenderHex(Buffer, A.SInt); 20868d75effSDimitry Andric break; 20968d75effSDimitry Andric case Diag::AK_UInt: 21068d75effSDimitry Andric if (A.UInt <= UINT64_MAX) 2115f757f3fSDimitry Andric Buffer->AppendF("%llu", (unsigned long long)A.UInt); 21268d75effSDimitry Andric else 21368d75effSDimitry Andric RenderHex(Buffer, A.UInt); 21468d75effSDimitry Andric break; 21568d75effSDimitry Andric case Diag::AK_Float: { 21668d75effSDimitry Andric // FIXME: Support floating-point formatting in sanitizer_common's 21768d75effSDimitry Andric // printf, and stop using snprintf here. 21868d75effSDimitry Andric char FloatBuffer[32]; 21968d75effSDimitry Andric #if SANITIZER_WINDOWS 22006c3fb27SDimitry Andric // On MSVC platforms, long doubles are equal to regular doubles. 22106c3fb27SDimitry Andric // In MinGW environments on x86, long doubles are 80 bit, but here, 22206c3fb27SDimitry Andric // we're calling an MS CRT provided printf function which considers 22306c3fb27SDimitry Andric // long doubles to be 64 bit. Just cast the float value to a regular 22406c3fb27SDimitry Andric // double to avoid the potential ambiguity in MinGW mode. 22506c3fb27SDimitry Andric sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%g", (double)A.Float); 22668d75effSDimitry Andric #else 22768d75effSDimitry Andric snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float); 22868d75effSDimitry Andric #endif 2295f757f3fSDimitry Andric Buffer->Append(FloatBuffer); 23068d75effSDimitry Andric break; 23168d75effSDimitry Andric } 23268d75effSDimitry Andric case Diag::AK_Pointer: 2335f757f3fSDimitry Andric Buffer->AppendF("%p", A.Pointer); 23468d75effSDimitry Andric break; 23568d75effSDimitry Andric } 23668d75effSDimitry Andric } 23768d75effSDimitry Andric } 23868d75effSDimitry Andric 23968d75effSDimitry Andric /// Find the earliest-starting range in Ranges which ends after Loc. 24068d75effSDimitry Andric static Range *upperBound(MemoryLocation Loc, Range *Ranges, 24168d75effSDimitry Andric unsigned NumRanges) { 24268d75effSDimitry Andric Range *Best = 0; 24368d75effSDimitry Andric for (unsigned I = 0; I != NumRanges; ++I) 24468d75effSDimitry Andric if (Ranges[I].getEnd().getMemoryLocation() > Loc && 24568d75effSDimitry Andric (!Best || 24668d75effSDimitry Andric Best->getStart().getMemoryLocation() > 24768d75effSDimitry Andric Ranges[I].getStart().getMemoryLocation())) 24868d75effSDimitry Andric Best = &Ranges[I]; 24968d75effSDimitry Andric return Best; 25068d75effSDimitry Andric } 25168d75effSDimitry Andric 25268d75effSDimitry Andric static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) { 25368d75effSDimitry Andric return (LHS < RHS) ? 0 : LHS - RHS; 25468d75effSDimitry Andric } 25568d75effSDimitry Andric 25668d75effSDimitry Andric static inline uptr addNoOverflow(uptr LHS, uptr RHS) { 25768d75effSDimitry Andric const uptr Limit = (uptr)-1; 25868d75effSDimitry Andric return (LHS > Limit - RHS) ? Limit : LHS + RHS; 25968d75effSDimitry Andric } 26068d75effSDimitry Andric 26168d75effSDimitry Andric /// Render a snippet of the address space near a location. 26268d75effSDimitry Andric static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc, 26368d75effSDimitry Andric Range *Ranges, unsigned NumRanges, 26468d75effSDimitry Andric const Diag::Arg *Args) { 26568d75effSDimitry Andric // Show at least the 8 bytes surrounding Loc. 26668d75effSDimitry Andric const unsigned MinBytesNearLoc = 4; 26768d75effSDimitry Andric MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc); 26868d75effSDimitry Andric MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc); 26968d75effSDimitry Andric MemoryLocation OrigMin = Min; 27068d75effSDimitry Andric for (unsigned I = 0; I < NumRanges; ++I) { 27168d75effSDimitry Andric Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); 27268d75effSDimitry Andric Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); 27368d75effSDimitry Andric } 27468d75effSDimitry Andric 27568d75effSDimitry Andric // If we have too many interesting bytes, prefer to show bytes after Loc. 27668d75effSDimitry Andric const unsigned BytesToShow = 32; 27768d75effSDimitry Andric if (Max - Min > BytesToShow) 27868d75effSDimitry Andric Min = __sanitizer::Min(Max - BytesToShow, OrigMin); 27968d75effSDimitry Andric Max = addNoOverflow(Min, BytesToShow); 28068d75effSDimitry Andric 28168d75effSDimitry Andric if (!IsAccessibleMemoryRange(Min, Max - Min)) { 28268d75effSDimitry Andric Printf("<memory cannot be printed>\n"); 28368d75effSDimitry Andric return; 28468d75effSDimitry Andric } 28568d75effSDimitry Andric 28668d75effSDimitry Andric // Emit data. 287fe6060f1SDimitry Andric InternalScopedString Buffer; 28868d75effSDimitry Andric for (uptr P = Min; P != Max; ++P) { 28968d75effSDimitry Andric unsigned char C = *reinterpret_cast<const unsigned char*>(P); 2905f757f3fSDimitry Andric Buffer.AppendF("%s%02x", (P % 8 == 0) ? " " : " ", C); 29168d75effSDimitry Andric } 2925f757f3fSDimitry Andric Buffer.AppendF("\n"); 29368d75effSDimitry Andric 29468d75effSDimitry Andric // Emit highlights. 2955f757f3fSDimitry Andric Buffer.Append(Decor.Highlight()); 29668d75effSDimitry Andric Range *InRange = upperBound(Min, Ranges, NumRanges); 29768d75effSDimitry Andric for (uptr P = Min; P != Max; ++P) { 29868d75effSDimitry Andric char Pad = ' ', Byte = ' '; 29968d75effSDimitry Andric if (InRange && InRange->getEnd().getMemoryLocation() == P) 30068d75effSDimitry Andric InRange = upperBound(P, Ranges, NumRanges); 30168d75effSDimitry Andric if (!InRange && P > Loc) 30268d75effSDimitry Andric break; 30368d75effSDimitry Andric if (InRange && InRange->getStart().getMemoryLocation() < P) 30468d75effSDimitry Andric Pad = '~'; 30568d75effSDimitry Andric if (InRange && InRange->getStart().getMemoryLocation() <= P) 30668d75effSDimitry Andric Byte = '~'; 30768d75effSDimitry Andric if (P % 8 == 0) 3085f757f3fSDimitry Andric Buffer.AppendF("%c", Pad); 3095f757f3fSDimitry Andric Buffer.AppendF("%c", Pad); 3105f757f3fSDimitry Andric Buffer.AppendF("%c", P == Loc ? '^' : Byte); 3115f757f3fSDimitry Andric Buffer.AppendF("%c", Byte); 31268d75effSDimitry Andric } 3135f757f3fSDimitry Andric Buffer.AppendF("%s\n", Decor.Default()); 31468d75effSDimitry Andric 31568d75effSDimitry Andric // Go over the line again, and print names for the ranges. 31668d75effSDimitry Andric InRange = 0; 31768d75effSDimitry Andric unsigned Spaces = 0; 31868d75effSDimitry Andric for (uptr P = Min; P != Max; ++P) { 31968d75effSDimitry Andric if (!InRange || InRange->getEnd().getMemoryLocation() == P) 32068d75effSDimitry Andric InRange = upperBound(P, Ranges, NumRanges); 32168d75effSDimitry Andric if (!InRange) 32268d75effSDimitry Andric break; 32368d75effSDimitry Andric 32468d75effSDimitry Andric Spaces += (P % 8) == 0 ? 2 : 1; 32568d75effSDimitry Andric 32668d75effSDimitry Andric if (InRange && InRange->getStart().getMemoryLocation() == P) { 32768d75effSDimitry Andric while (Spaces--) 3285f757f3fSDimitry Andric Buffer.AppendF(" "); 32968d75effSDimitry Andric RenderText(&Buffer, InRange->getText(), Args); 3305f757f3fSDimitry Andric Buffer.AppendF("\n"); 33168d75effSDimitry Andric // FIXME: We only support naming one range for now! 33268d75effSDimitry Andric break; 33368d75effSDimitry Andric } 33468d75effSDimitry Andric 33568d75effSDimitry Andric Spaces += 2; 33668d75effSDimitry Andric } 33768d75effSDimitry Andric 33868d75effSDimitry Andric Printf("%s", Buffer.data()); 33968d75effSDimitry Andric // FIXME: Print names for anything we can identify within the line: 34068d75effSDimitry Andric // 34168d75effSDimitry Andric // * If we can identify the memory itself as belonging to a particular 34268d75effSDimitry Andric // global, stack variable, or dynamic allocation, then do so. 34368d75effSDimitry Andric // 34468d75effSDimitry Andric // * If we have a pointer-size, pointer-aligned range highlighted, 34568d75effSDimitry Andric // determine whether the value of that range is a pointer to an 34668d75effSDimitry Andric // entity which we can name, and if so, print that name. 34768d75effSDimitry Andric // 34868d75effSDimitry Andric // This needs an external symbolizer, or (preferably) ASan instrumentation. 34968d75effSDimitry Andric } 35068d75effSDimitry Andric 35168d75effSDimitry Andric Diag::~Diag() { 35268d75effSDimitry Andric // All diagnostics should be printed under report mutex. 35368d75effSDimitry Andric ScopedReport::CheckLocked(); 35468d75effSDimitry Andric Decorator Decor; 355fe6060f1SDimitry Andric InternalScopedString Buffer; 35668d75effSDimitry Andric 35768d75effSDimitry Andric // Prepare a report that a monitor process can inspect. 35868d75effSDimitry Andric if (Level == DL_Error) { 35968d75effSDimitry Andric RenderText(&Buffer, Message, Args); 36068d75effSDimitry Andric UndefinedBehaviorReport UBR{ConvertTypeToString(ET), Loc, Buffer}; 36168d75effSDimitry Andric Buffer.clear(); 36268d75effSDimitry Andric } 36368d75effSDimitry Andric 3645f757f3fSDimitry Andric Buffer.Append(Decor.Bold()); 36568d75effSDimitry Andric RenderLocation(&Buffer, Loc); 3665f757f3fSDimitry Andric Buffer.AppendF(":"); 36768d75effSDimitry Andric 36868d75effSDimitry Andric switch (Level) { 36968d75effSDimitry Andric case DL_Error: 3705f757f3fSDimitry Andric Buffer.AppendF("%s runtime error: %s%s", Decor.Warning(), Decor.Default(), 37168d75effSDimitry Andric Decor.Bold()); 37268d75effSDimitry Andric break; 37368d75effSDimitry Andric 37468d75effSDimitry Andric case DL_Note: 3755f757f3fSDimitry Andric Buffer.AppendF("%s note: %s", Decor.Note(), Decor.Default()); 37668d75effSDimitry Andric break; 37768d75effSDimitry Andric } 37868d75effSDimitry Andric 37968d75effSDimitry Andric RenderText(&Buffer, Message, Args); 38068d75effSDimitry Andric 3815f757f3fSDimitry Andric Buffer.AppendF("%s\n", Decor.Default()); 38268d75effSDimitry Andric Printf("%s", Buffer.data()); 38368d75effSDimitry Andric 38468d75effSDimitry Andric if (Loc.isMemoryLocation()) 38568d75effSDimitry Andric PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args); 38668d75effSDimitry Andric } 38768d75effSDimitry Andric 38868d75effSDimitry Andric ScopedReport::Initializer::Initializer() { InitAsStandaloneIfNecessary(); } 38968d75effSDimitry Andric 39068d75effSDimitry Andric ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc, 39168d75effSDimitry Andric ErrorType Type) 39268d75effSDimitry Andric : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {} 39368d75effSDimitry Andric 39468d75effSDimitry Andric ScopedReport::~ScopedReport() { 39568d75effSDimitry Andric MaybePrintStackTrace(Opts.pc, Opts.bp); 39668d75effSDimitry Andric MaybeReportErrorSummary(SummaryLoc, Type); 397fe6060f1SDimitry Andric 398fe6060f1SDimitry Andric if (common_flags()->print_module_map >= 2) 399fe6060f1SDimitry Andric DumpProcessMap(); 400fe6060f1SDimitry Andric 40168d75effSDimitry Andric if (flags()->halt_on_error) 40268d75effSDimitry Andric Die(); 40368d75effSDimitry Andric } 40468d75effSDimitry Andric 405*0fca6ea1SDimitry Andric alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)]; 40668d75effSDimitry Andric static SuppressionContext *suppression_ctx = nullptr; 40768d75effSDimitry Andric static const char kVptrCheck[] = "vptr_check"; 40868d75effSDimitry Andric static const char *kSuppressionTypes[] = { 40968d75effSDimitry Andric #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName, 41068d75effSDimitry Andric #include "ubsan_checks.inc" 41168d75effSDimitry Andric #undef UBSAN_CHECK 41268d75effSDimitry Andric kVptrCheck, 41368d75effSDimitry Andric }; 41468d75effSDimitry Andric 41568d75effSDimitry Andric void __ubsan::InitializeSuppressions() { 41668d75effSDimitry Andric CHECK_EQ(nullptr, suppression_ctx); 41768d75effSDimitry Andric suppression_ctx = new (suppression_placeholder) 41868d75effSDimitry Andric SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); 41968d75effSDimitry Andric suppression_ctx->ParseFromFile(flags()->suppressions); 42068d75effSDimitry Andric } 42168d75effSDimitry Andric 42268d75effSDimitry Andric bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) { 42368d75effSDimitry Andric InitAsStandaloneIfNecessary(); 42468d75effSDimitry Andric CHECK(suppression_ctx); 42568d75effSDimitry Andric Suppression *s; 42668d75effSDimitry Andric return suppression_ctx->Match(TypeName, kVptrCheck, &s); 42768d75effSDimitry Andric } 42868d75effSDimitry Andric 42968d75effSDimitry Andric bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) { 43068d75effSDimitry Andric InitAsStandaloneIfNecessary(); 43168d75effSDimitry Andric CHECK(suppression_ctx); 43268d75effSDimitry Andric const char *SuppType = ConvertTypeToFlagName(ET); 43368d75effSDimitry Andric // Fast path: don't symbolize PC if there is no suppressions for given UB 43468d75effSDimitry Andric // type. 43568d75effSDimitry Andric if (!suppression_ctx->HasSuppressionType(SuppType)) 43668d75effSDimitry Andric return false; 43768d75effSDimitry Andric Suppression *s = nullptr; 43868d75effSDimitry Andric // Suppress by file name known to runtime. 43968d75effSDimitry Andric if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s)) 44068d75effSDimitry Andric return true; 44168d75effSDimitry Andric // Suppress by module name. 44268d75effSDimitry Andric if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) { 44368d75effSDimitry Andric if (suppression_ctx->Match(Module, SuppType, &s)) 44468d75effSDimitry Andric return true; 44568d75effSDimitry Andric } 44668d75effSDimitry Andric // Suppress by function or source file name from debug info. 44768d75effSDimitry Andric SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC)); 44868d75effSDimitry Andric const AddressInfo &AI = Stack.get()->info; 44968d75effSDimitry Andric return suppression_ctx->Match(AI.function, SuppType, &s) || 45068d75effSDimitry Andric suppression_ctx->Match(AI.file, SuppType, &s); 45168d75effSDimitry Andric } 45268d75effSDimitry Andric 45368d75effSDimitry Andric #endif // CAN_SANITIZE_UB 454