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. 3568d75effSDimitry Andric void ubsan_GetStackTrace(BufferedStackTrace *stack, uptr max_depth, 3668d75effSDimitry Andric uptr pc, uptr bp, void *context, bool fast) { 3768d75effSDimitry Andric uptr top = 0; 3868d75effSDimitry Andric uptr bottom = 0; 3968d75effSDimitry Andric if (StackTrace::WillUseFastUnwind(fast)) { 4068d75effSDimitry Andric GetThreadStackTopAndBottom(false, &top, &bottom); 4168d75effSDimitry Andric stack->Unwind(max_depth, pc, bp, nullptr, top, bottom, true); 4268d75effSDimitry Andric } else 4368d75effSDimitry Andric stack->Unwind(max_depth, pc, bp, context, 0, 0, false); 4468d75effSDimitry Andric } 4568d75effSDimitry Andric 4668d75effSDimitry Andric static void MaybePrintStackTrace(uptr pc, uptr bp) { 4768d75effSDimitry Andric // We assume that flags are already parsed, as UBSan runtime 4868d75effSDimitry Andric // will definitely be called when we print the first diagnostics message. 4968d75effSDimitry Andric if (!flags()->print_stacktrace) 5068d75effSDimitry Andric return; 5168d75effSDimitry Andric 5268d75effSDimitry Andric BufferedStackTrace stack; 5368d75effSDimitry Andric ubsan_GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr, 5468d75effSDimitry Andric common_flags()->fast_unwind_on_fatal); 5568d75effSDimitry Andric stack.Print(); 5668d75effSDimitry Andric } 5768d75effSDimitry Andric 5868d75effSDimitry Andric static const char *ConvertTypeToString(ErrorType Type) { 5968d75effSDimitry Andric switch (Type) { 6068d75effSDimitry Andric #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \ 6168d75effSDimitry Andric case ErrorType::Name: \ 6268d75effSDimitry Andric return SummaryKind; 6368d75effSDimitry Andric #include "ubsan_checks.inc" 6468d75effSDimitry Andric #undef UBSAN_CHECK 6568d75effSDimitry Andric } 6668d75effSDimitry Andric UNREACHABLE("unknown ErrorType!"); 6768d75effSDimitry Andric } 6868d75effSDimitry Andric 6968d75effSDimitry Andric static const char *ConvertTypeToFlagName(ErrorType Type) { 7068d75effSDimitry Andric switch (Type) { 7168d75effSDimitry Andric #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \ 7268d75effSDimitry Andric case ErrorType::Name: \ 7368d75effSDimitry Andric return FSanitizeFlagName; 7468d75effSDimitry Andric #include "ubsan_checks.inc" 7568d75effSDimitry Andric #undef UBSAN_CHECK 7668d75effSDimitry Andric } 7768d75effSDimitry Andric UNREACHABLE("unknown ErrorType!"); 7868d75effSDimitry Andric } 7968d75effSDimitry Andric 8068d75effSDimitry Andric static void MaybeReportErrorSummary(Location Loc, ErrorType Type) { 8168d75effSDimitry Andric if (!common_flags()->print_summary) 8268d75effSDimitry Andric return; 8368d75effSDimitry Andric if (!flags()->report_error_type) 8468d75effSDimitry Andric Type = ErrorType::GenericUB; 8568d75effSDimitry Andric const char *ErrorKind = ConvertTypeToString(Type); 8668d75effSDimitry Andric if (Loc.isSourceLocation()) { 8768d75effSDimitry Andric SourceLocation SLoc = Loc.getSourceLocation(); 8868d75effSDimitry Andric if (!SLoc.isInvalid()) { 8968d75effSDimitry Andric AddressInfo AI; 9068d75effSDimitry Andric AI.file = internal_strdup(SLoc.getFilename()); 9168d75effSDimitry Andric AI.line = SLoc.getLine(); 9268d75effSDimitry Andric AI.column = SLoc.getColumn(); 9368d75effSDimitry Andric AI.function = internal_strdup(""); // Avoid printing ?? as function name. 9468d75effSDimitry Andric ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); 9568d75effSDimitry Andric AI.Clear(); 9668d75effSDimitry Andric return; 9768d75effSDimitry Andric } 9868d75effSDimitry Andric } else if (Loc.isSymbolizedStack()) { 9968d75effSDimitry Andric const AddressInfo &AI = Loc.getSymbolizedStack()->info; 10068d75effSDimitry Andric ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName()); 10168d75effSDimitry Andric return; 10268d75effSDimitry Andric } 10368d75effSDimitry Andric ReportErrorSummary(ErrorKind, GetSanititizerToolName()); 10468d75effSDimitry Andric } 10568d75effSDimitry Andric 10668d75effSDimitry Andric namespace { 10768d75effSDimitry Andric class Decorator : public SanitizerCommonDecorator { 10868d75effSDimitry Andric public: 10968d75effSDimitry Andric Decorator() : SanitizerCommonDecorator() {} 11068d75effSDimitry Andric const char *Highlight() const { return Green(); } 11168d75effSDimitry Andric const char *Note() const { return Black(); } 11268d75effSDimitry Andric }; 11368d75effSDimitry Andric } 11468d75effSDimitry Andric 11568d75effSDimitry Andric SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) { 11668d75effSDimitry Andric InitAsStandaloneIfNecessary(); 11768d75effSDimitry Andric return Symbolizer::GetOrInit()->SymbolizePC(PC); 11868d75effSDimitry Andric } 11968d75effSDimitry Andric 12068d75effSDimitry Andric Diag &Diag::operator<<(const TypeDescriptor &V) { 12168d75effSDimitry Andric return AddArg(V.getTypeName()); 12268d75effSDimitry Andric } 12368d75effSDimitry Andric 12468d75effSDimitry Andric Diag &Diag::operator<<(const Value &V) { 12568d75effSDimitry Andric if (V.getType().isSignedIntegerTy()) 12668d75effSDimitry Andric AddArg(V.getSIntValue()); 12768d75effSDimitry Andric else if (V.getType().isUnsignedIntegerTy()) 12868d75effSDimitry Andric AddArg(V.getUIntValue()); 12968d75effSDimitry Andric else if (V.getType().isFloatTy()) 13068d75effSDimitry Andric AddArg(V.getFloatValue()); 13168d75effSDimitry Andric else 13268d75effSDimitry Andric AddArg("<unknown>"); 13368d75effSDimitry Andric return *this; 13468d75effSDimitry Andric } 13568d75effSDimitry Andric 13668d75effSDimitry Andric /// Hexadecimal printing for numbers too large for Printf to handle directly. 13768d75effSDimitry Andric static void RenderHex(InternalScopedString *Buffer, UIntMax Val) { 13868d75effSDimitry Andric #if HAVE_INT128_T 13968d75effSDimitry Andric Buffer->append("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96), 14068d75effSDimitry Andric (unsigned int)(Val >> 64), (unsigned int)(Val >> 32), 14168d75effSDimitry Andric (unsigned int)(Val)); 14268d75effSDimitry Andric #else 14368d75effSDimitry Andric UNREACHABLE("long long smaller than 64 bits?"); 14468d75effSDimitry Andric #endif 14568d75effSDimitry Andric } 14668d75effSDimitry Andric 14768d75effSDimitry Andric static void RenderLocation(InternalScopedString *Buffer, Location Loc) { 14868d75effSDimitry Andric switch (Loc.getKind()) { 14968d75effSDimitry Andric case Location::LK_Source: { 15068d75effSDimitry Andric SourceLocation SLoc = Loc.getSourceLocation(); 15168d75effSDimitry Andric if (SLoc.isInvalid()) 15268d75effSDimitry Andric Buffer->append("<unknown>"); 15368d75effSDimitry Andric else 15468d75effSDimitry Andric RenderSourceLocation(Buffer, SLoc.getFilename(), SLoc.getLine(), 15568d75effSDimitry Andric SLoc.getColumn(), common_flags()->symbolize_vs_style, 15668d75effSDimitry Andric common_flags()->strip_path_prefix); 15768d75effSDimitry Andric return; 15868d75effSDimitry Andric } 15968d75effSDimitry Andric case Location::LK_Memory: 16068d75effSDimitry Andric Buffer->append("%p", Loc.getMemoryLocation()); 16168d75effSDimitry Andric return; 16268d75effSDimitry Andric case Location::LK_Symbolized: { 16368d75effSDimitry Andric const AddressInfo &Info = Loc.getSymbolizedStack()->info; 16468d75effSDimitry Andric if (Info.file) 16568d75effSDimitry Andric RenderSourceLocation(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) 16968d75effSDimitry Andric RenderModuleLocation(Buffer, Info.module, Info.module_offset, 17068d75effSDimitry Andric Info.module_arch, common_flags()->strip_path_prefix); 17168d75effSDimitry Andric else 17268d75effSDimitry Andric Buffer->append("%p", Info.address); 17368d75effSDimitry Andric return; 17468d75effSDimitry Andric } 17568d75effSDimitry Andric case Location::LK_Null: 17668d75effSDimitry Andric Buffer->append("<unknown>"); 17768d75effSDimitry Andric return; 17868d75effSDimitry Andric } 17968d75effSDimitry Andric } 18068d75effSDimitry Andric 18168d75effSDimitry Andric static void RenderText(InternalScopedString *Buffer, const char *Message, 18268d75effSDimitry Andric const Diag::Arg *Args) { 18368d75effSDimitry Andric for (const char *Msg = Message; *Msg; ++Msg) { 18468d75effSDimitry Andric if (*Msg != '%') { 18568d75effSDimitry Andric Buffer->append("%c", *Msg); 18668d75effSDimitry Andric continue; 18768d75effSDimitry Andric } 18868d75effSDimitry Andric const Diag::Arg &A = Args[*++Msg - '0']; 18968d75effSDimitry Andric switch (A.Kind) { 19068d75effSDimitry Andric case Diag::AK_String: 19168d75effSDimitry Andric Buffer->append("%s", A.String); 19268d75effSDimitry Andric break; 19368d75effSDimitry Andric case Diag::AK_TypeName: { 19468d75effSDimitry Andric if (SANITIZER_WINDOWS) 19568d75effSDimitry Andric // The Windows implementation demangles names early. 19668d75effSDimitry Andric Buffer->append("'%s'", A.String); 19768d75effSDimitry Andric else 19868d75effSDimitry Andric Buffer->append("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); 19968d75effSDimitry Andric break; 20068d75effSDimitry Andric } 20168d75effSDimitry Andric case Diag::AK_SInt: 20268d75effSDimitry Andric // 'long long' is guaranteed to be at least 64 bits wide. 20368d75effSDimitry Andric if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX) 20468d75effSDimitry Andric Buffer->append("%lld", (long long)A.SInt); 20568d75effSDimitry Andric else 20668d75effSDimitry Andric RenderHex(Buffer, A.SInt); 20768d75effSDimitry Andric break; 20868d75effSDimitry Andric case Diag::AK_UInt: 20968d75effSDimitry Andric if (A.UInt <= UINT64_MAX) 21068d75effSDimitry Andric Buffer->append("%llu", (unsigned long long)A.UInt); 21168d75effSDimitry Andric else 21268d75effSDimitry Andric RenderHex(Buffer, A.UInt); 21368d75effSDimitry Andric break; 21468d75effSDimitry Andric case Diag::AK_Float: { 21568d75effSDimitry Andric // FIXME: Support floating-point formatting in sanitizer_common's 21668d75effSDimitry Andric // printf, and stop using snprintf here. 21768d75effSDimitry Andric char FloatBuffer[32]; 21868d75effSDimitry Andric #if SANITIZER_WINDOWS 21968d75effSDimitry Andric sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float); 22068d75effSDimitry Andric #else 22168d75effSDimitry Andric snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float); 22268d75effSDimitry Andric #endif 22368d75effSDimitry Andric Buffer->append("%s", FloatBuffer); 22468d75effSDimitry Andric break; 22568d75effSDimitry Andric } 22668d75effSDimitry Andric case Diag::AK_Pointer: 22768d75effSDimitry Andric Buffer->append("%p", A.Pointer); 22868d75effSDimitry Andric break; 22968d75effSDimitry Andric } 23068d75effSDimitry Andric } 23168d75effSDimitry Andric } 23268d75effSDimitry Andric 23368d75effSDimitry Andric /// Find the earliest-starting range in Ranges which ends after Loc. 23468d75effSDimitry Andric static Range *upperBound(MemoryLocation Loc, Range *Ranges, 23568d75effSDimitry Andric unsigned NumRanges) { 23668d75effSDimitry Andric Range *Best = 0; 23768d75effSDimitry Andric for (unsigned I = 0; I != NumRanges; ++I) 23868d75effSDimitry Andric if (Ranges[I].getEnd().getMemoryLocation() > Loc && 23968d75effSDimitry Andric (!Best || 24068d75effSDimitry Andric Best->getStart().getMemoryLocation() > 24168d75effSDimitry Andric Ranges[I].getStart().getMemoryLocation())) 24268d75effSDimitry Andric Best = &Ranges[I]; 24368d75effSDimitry Andric return Best; 24468d75effSDimitry Andric } 24568d75effSDimitry Andric 24668d75effSDimitry Andric static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) { 24768d75effSDimitry Andric return (LHS < RHS) ? 0 : LHS - RHS; 24868d75effSDimitry Andric } 24968d75effSDimitry Andric 25068d75effSDimitry Andric static inline uptr addNoOverflow(uptr LHS, uptr RHS) { 25168d75effSDimitry Andric const uptr Limit = (uptr)-1; 25268d75effSDimitry Andric return (LHS > Limit - RHS) ? Limit : LHS + RHS; 25368d75effSDimitry Andric } 25468d75effSDimitry Andric 25568d75effSDimitry Andric /// Render a snippet of the address space near a location. 25668d75effSDimitry Andric static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc, 25768d75effSDimitry Andric Range *Ranges, unsigned NumRanges, 25868d75effSDimitry Andric const Diag::Arg *Args) { 25968d75effSDimitry Andric // Show at least the 8 bytes surrounding Loc. 26068d75effSDimitry Andric const unsigned MinBytesNearLoc = 4; 26168d75effSDimitry Andric MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc); 26268d75effSDimitry Andric MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc); 26368d75effSDimitry Andric MemoryLocation OrigMin = Min; 26468d75effSDimitry Andric for (unsigned I = 0; I < NumRanges; ++I) { 26568d75effSDimitry Andric Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); 26668d75effSDimitry Andric Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); 26768d75effSDimitry Andric } 26868d75effSDimitry Andric 26968d75effSDimitry Andric // If we have too many interesting bytes, prefer to show bytes after Loc. 27068d75effSDimitry Andric const unsigned BytesToShow = 32; 27168d75effSDimitry Andric if (Max - Min > BytesToShow) 27268d75effSDimitry Andric Min = __sanitizer::Min(Max - BytesToShow, OrigMin); 27368d75effSDimitry Andric Max = addNoOverflow(Min, BytesToShow); 27468d75effSDimitry Andric 27568d75effSDimitry Andric if (!IsAccessibleMemoryRange(Min, Max - Min)) { 27668d75effSDimitry Andric Printf("<memory cannot be printed>\n"); 27768d75effSDimitry Andric return; 27868d75effSDimitry Andric } 27968d75effSDimitry Andric 28068d75effSDimitry Andric // Emit data. 281*fe6060f1SDimitry Andric InternalScopedString Buffer; 28268d75effSDimitry Andric for (uptr P = Min; P != Max; ++P) { 28368d75effSDimitry Andric unsigned char C = *reinterpret_cast<const unsigned char*>(P); 28468d75effSDimitry Andric Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C); 28568d75effSDimitry Andric } 28668d75effSDimitry Andric Buffer.append("\n"); 28768d75effSDimitry Andric 28868d75effSDimitry Andric // Emit highlights. 28968d75effSDimitry Andric Buffer.append(Decor.Highlight()); 29068d75effSDimitry Andric Range *InRange = upperBound(Min, Ranges, NumRanges); 29168d75effSDimitry Andric for (uptr P = Min; P != Max; ++P) { 29268d75effSDimitry Andric char Pad = ' ', Byte = ' '; 29368d75effSDimitry Andric if (InRange && InRange->getEnd().getMemoryLocation() == P) 29468d75effSDimitry Andric InRange = upperBound(P, Ranges, NumRanges); 29568d75effSDimitry Andric if (!InRange && P > Loc) 29668d75effSDimitry Andric break; 29768d75effSDimitry Andric if (InRange && InRange->getStart().getMemoryLocation() < P) 29868d75effSDimitry Andric Pad = '~'; 29968d75effSDimitry Andric if (InRange && InRange->getStart().getMemoryLocation() <= P) 30068d75effSDimitry Andric Byte = '~'; 30168d75effSDimitry Andric if (P % 8 == 0) 30268d75effSDimitry Andric Buffer.append("%c", Pad); 30368d75effSDimitry Andric Buffer.append("%c", Pad); 30468d75effSDimitry Andric Buffer.append("%c", P == Loc ? '^' : Byte); 30568d75effSDimitry Andric Buffer.append("%c", Byte); 30668d75effSDimitry Andric } 30768d75effSDimitry Andric Buffer.append("%s\n", Decor.Default()); 30868d75effSDimitry Andric 30968d75effSDimitry Andric // Go over the line again, and print names for the ranges. 31068d75effSDimitry Andric InRange = 0; 31168d75effSDimitry Andric unsigned Spaces = 0; 31268d75effSDimitry Andric for (uptr P = Min; P != Max; ++P) { 31368d75effSDimitry Andric if (!InRange || InRange->getEnd().getMemoryLocation() == P) 31468d75effSDimitry Andric InRange = upperBound(P, Ranges, NumRanges); 31568d75effSDimitry Andric if (!InRange) 31668d75effSDimitry Andric break; 31768d75effSDimitry Andric 31868d75effSDimitry Andric Spaces += (P % 8) == 0 ? 2 : 1; 31968d75effSDimitry Andric 32068d75effSDimitry Andric if (InRange && InRange->getStart().getMemoryLocation() == P) { 32168d75effSDimitry Andric while (Spaces--) 32268d75effSDimitry Andric Buffer.append(" "); 32368d75effSDimitry Andric RenderText(&Buffer, InRange->getText(), Args); 32468d75effSDimitry Andric Buffer.append("\n"); 32568d75effSDimitry Andric // FIXME: We only support naming one range for now! 32668d75effSDimitry Andric break; 32768d75effSDimitry Andric } 32868d75effSDimitry Andric 32968d75effSDimitry Andric Spaces += 2; 33068d75effSDimitry Andric } 33168d75effSDimitry Andric 33268d75effSDimitry Andric Printf("%s", Buffer.data()); 33368d75effSDimitry Andric // FIXME: Print names for anything we can identify within the line: 33468d75effSDimitry Andric // 33568d75effSDimitry Andric // * If we can identify the memory itself as belonging to a particular 33668d75effSDimitry Andric // global, stack variable, or dynamic allocation, then do so. 33768d75effSDimitry Andric // 33868d75effSDimitry Andric // * If we have a pointer-size, pointer-aligned range highlighted, 33968d75effSDimitry Andric // determine whether the value of that range is a pointer to an 34068d75effSDimitry Andric // entity which we can name, and if so, print that name. 34168d75effSDimitry Andric // 34268d75effSDimitry Andric // This needs an external symbolizer, or (preferably) ASan instrumentation. 34368d75effSDimitry Andric } 34468d75effSDimitry Andric 34568d75effSDimitry Andric Diag::~Diag() { 34668d75effSDimitry Andric // All diagnostics should be printed under report mutex. 34768d75effSDimitry Andric ScopedReport::CheckLocked(); 34868d75effSDimitry Andric Decorator Decor; 349*fe6060f1SDimitry Andric InternalScopedString Buffer; 35068d75effSDimitry Andric 35168d75effSDimitry Andric // Prepare a report that a monitor process can inspect. 35268d75effSDimitry Andric if (Level == DL_Error) { 35368d75effSDimitry Andric RenderText(&Buffer, Message, Args); 35468d75effSDimitry Andric UndefinedBehaviorReport UBR{ConvertTypeToString(ET), Loc, Buffer}; 35568d75effSDimitry Andric Buffer.clear(); 35668d75effSDimitry Andric } 35768d75effSDimitry Andric 35868d75effSDimitry Andric Buffer.append(Decor.Bold()); 35968d75effSDimitry Andric RenderLocation(&Buffer, Loc); 36068d75effSDimitry Andric Buffer.append(":"); 36168d75effSDimitry Andric 36268d75effSDimitry Andric switch (Level) { 36368d75effSDimitry Andric case DL_Error: 36468d75effSDimitry Andric Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.Default(), 36568d75effSDimitry Andric Decor.Bold()); 36668d75effSDimitry Andric break; 36768d75effSDimitry Andric 36868d75effSDimitry Andric case DL_Note: 36968d75effSDimitry Andric Buffer.append("%s note: %s", Decor.Note(), Decor.Default()); 37068d75effSDimitry Andric break; 37168d75effSDimitry Andric } 37268d75effSDimitry Andric 37368d75effSDimitry Andric RenderText(&Buffer, Message, Args); 37468d75effSDimitry Andric 37568d75effSDimitry Andric Buffer.append("%s\n", Decor.Default()); 37668d75effSDimitry Andric Printf("%s", Buffer.data()); 37768d75effSDimitry Andric 37868d75effSDimitry Andric if (Loc.isMemoryLocation()) 37968d75effSDimitry Andric PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args); 38068d75effSDimitry Andric } 38168d75effSDimitry Andric 38268d75effSDimitry Andric ScopedReport::Initializer::Initializer() { InitAsStandaloneIfNecessary(); } 38368d75effSDimitry Andric 38468d75effSDimitry Andric ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc, 38568d75effSDimitry Andric ErrorType Type) 38668d75effSDimitry Andric : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {} 38768d75effSDimitry Andric 38868d75effSDimitry Andric ScopedReport::~ScopedReport() { 38968d75effSDimitry Andric MaybePrintStackTrace(Opts.pc, Opts.bp); 39068d75effSDimitry Andric MaybeReportErrorSummary(SummaryLoc, Type); 391*fe6060f1SDimitry Andric 392*fe6060f1SDimitry Andric if (common_flags()->print_module_map >= 2) 393*fe6060f1SDimitry Andric DumpProcessMap(); 394*fe6060f1SDimitry Andric 39568d75effSDimitry Andric if (flags()->halt_on_error) 39668d75effSDimitry Andric Die(); 39768d75effSDimitry Andric } 39868d75effSDimitry Andric 39968d75effSDimitry Andric ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; 40068d75effSDimitry Andric static SuppressionContext *suppression_ctx = nullptr; 40168d75effSDimitry Andric static const char kVptrCheck[] = "vptr_check"; 40268d75effSDimitry Andric static const char *kSuppressionTypes[] = { 40368d75effSDimitry Andric #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName, 40468d75effSDimitry Andric #include "ubsan_checks.inc" 40568d75effSDimitry Andric #undef UBSAN_CHECK 40668d75effSDimitry Andric kVptrCheck, 40768d75effSDimitry Andric }; 40868d75effSDimitry Andric 40968d75effSDimitry Andric void __ubsan::InitializeSuppressions() { 41068d75effSDimitry Andric CHECK_EQ(nullptr, suppression_ctx); 41168d75effSDimitry Andric suppression_ctx = new (suppression_placeholder) 41268d75effSDimitry Andric SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); 41368d75effSDimitry Andric suppression_ctx->ParseFromFile(flags()->suppressions); 41468d75effSDimitry Andric } 41568d75effSDimitry Andric 41668d75effSDimitry Andric bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) { 41768d75effSDimitry Andric InitAsStandaloneIfNecessary(); 41868d75effSDimitry Andric CHECK(suppression_ctx); 41968d75effSDimitry Andric Suppression *s; 42068d75effSDimitry Andric return suppression_ctx->Match(TypeName, kVptrCheck, &s); 42168d75effSDimitry Andric } 42268d75effSDimitry Andric 42368d75effSDimitry Andric bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) { 42468d75effSDimitry Andric InitAsStandaloneIfNecessary(); 42568d75effSDimitry Andric CHECK(suppression_ctx); 42668d75effSDimitry Andric const char *SuppType = ConvertTypeToFlagName(ET); 42768d75effSDimitry Andric // Fast path: don't symbolize PC if there is no suppressions for given UB 42868d75effSDimitry Andric // type. 42968d75effSDimitry Andric if (!suppression_ctx->HasSuppressionType(SuppType)) 43068d75effSDimitry Andric return false; 43168d75effSDimitry Andric Suppression *s = nullptr; 43268d75effSDimitry Andric // Suppress by file name known to runtime. 43368d75effSDimitry Andric if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s)) 43468d75effSDimitry Andric return true; 43568d75effSDimitry Andric // Suppress by module name. 43668d75effSDimitry Andric if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) { 43768d75effSDimitry Andric if (suppression_ctx->Match(Module, SuppType, &s)) 43868d75effSDimitry Andric return true; 43968d75effSDimitry Andric } 44068d75effSDimitry Andric // Suppress by function or source file name from debug info. 44168d75effSDimitry Andric SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC)); 44268d75effSDimitry Andric const AddressInfo &AI = Stack.get()->info; 44368d75effSDimitry Andric return suppression_ctx->Match(AI.function, SuppType, &s) || 44468d75effSDimitry Andric suppression_ctx->Match(AI.file, SuppType, &s); 44568d75effSDimitry Andric } 44668d75effSDimitry Andric 44768d75effSDimitry Andric #endif // CAN_SANITIZE_UB 448