xref: /llvm-project/compiler-rt/lib/ubsan/ubsan_diag.cpp (revision aacd1afa1ed2a72464cab8586edadbcd2c6bb47c)
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