]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libsanitizer/ubsan/ubsan_diag.cc
[libsanitizer merge from upstream r218156]
[thirdparty/gcc.git] / libsanitizer / ubsan / ubsan_diag.cc
index 1dfe7255f68371c40454591373f2b622a745fed7..828127ab84d95b5e711acdd73aef834ad2185ffb 100644 (file)
@@ -10,9 +10,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ubsan_diag.h"
-#include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_libc.h"
+#include "ubsan_init.h"
+#include "ubsan_flags.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 
 using namespace __ubsan;
 
-static void InitializeSanitizerCommon() {
-  static StaticSpinMutex init_mu;
-  SpinMutexLock l(&init_mu);
-  static bool initialized;
-  if (initialized)
-   return;
-  if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
-    // UBSan is run in a standalone mode. Initialize it now.
-    SanitizerToolName = "UndefinedBehaviorSanitizer";
-    CommonFlags *cf = common_flags();
-    SetCommonFlagsDefaults(cf);
-    cf->print_summary = false;
+static void MaybePrintStackTrace(uptr pc, uptr bp) {
+  // We assume that flags are already parsed: InitIfNecessary
+  // will definitely be called when we print the first diagnostics message.
+  if (!flags()->print_stacktrace)
+    return;
+  // We can only use slow unwind, as we don't have any information about stack
+  // top/bottom.
+  // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
+  // fetch stack top/bottom information if we have it (e.g. if we're running
+  // under ASan).
+  if (StackTrace::WillUseFastUnwind(false))
+    return;
+  StackTrace stack;
+  stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+  stack.Print();
+}
+
+static void MaybeReportErrorSummary(Location Loc) {
+  if (!common_flags()->print_summary)
+    return;
+  // Don't try to unwind the stack trace in UBSan summaries: just use the
+  // provided location.
+  if (Loc.isSourceLocation()) {
+    SourceLocation SLoc = Loc.getSourceLocation();
+    if (!SLoc.isInvalid()) {
+      ReportErrorSummary("runtime-error", SLoc.getFilename(), SLoc.getLine(),
+                         "");
+      return;
+    }
   }
-  initialized = true;
+  ReportErrorSummary("runtime-error");
+}
+
+namespace {
+class Decorator : public SanitizerCommonDecorator {
+ public:
+  Decorator() : SanitizerCommonDecorator() {}
+  const char *Highlight() const { return Green(); }
+  const char *EndHighlight() const { return Default(); }
+  const char *Note() const { return Black(); }
+  const char *EndNote() const { return Default(); }
+};
 }
 
 Location __ubsan::getCallerLocation(uptr CallerLoc) {
@@ -47,12 +74,11 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) {
 Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
   if (!Loc)
     return Location();
-  // FIXME: We may need to run initialization earlier.
-  InitializeSanitizerCommon();
+  InitIfNecessary();
 
   AddressInfo Info;
-  if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) ||
-      !Info.module || !*Info.module)
+  if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) || !Info.module ||
+      !*Info.module)
     return Location(Loc);
 
   if (FName && Info.function)
@@ -181,36 +207,49 @@ static Range *upperBound(MemoryLocation Loc, Range *Ranges,
   return Best;
 }
 
+static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) {
+  return (LHS < RHS) ? 0 : LHS - RHS;
+}
+
+static inline uptr addNoOverflow(uptr LHS, uptr RHS) {
+  const uptr Limit = (uptr)-1;
+  return (LHS > Limit - RHS) ? Limit : LHS + RHS;
+}
+
 /// Render a snippet of the address space near a location.
-static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
-                                MemoryLocation Loc,
+static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
                                 Range *Ranges, unsigned NumRanges,
                                 const Diag::Arg *Args) {
-  const unsigned BytesToShow = 32;
-  const unsigned MinBytesNearLoc = 4;
-
   // Show at least the 8 bytes surrounding Loc.
-  MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
+  const unsigned MinBytesNearLoc = 4;
+  MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc);
+  MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc);
+  MemoryLocation OrigMin = Min;
   for (unsigned I = 0; I < NumRanges; ++I) {
     Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
     Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
   }
 
   // If we have too many interesting bytes, prefer to show bytes after Loc.
+  const unsigned BytesToShow = 32;
   if (Max - Min > BytesToShow)
-    Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
-  Max = Min + BytesToShow;
+    Min = __sanitizer::Min(Max - BytesToShow, OrigMin);
+  Max = addNoOverflow(Min, BytesToShow);
+
+  if (!IsAccessibleMemoryRange(Min, Max - Min)) {
+    Printf("<memory cannot be printed>\n");
+    return;
+  }
 
   // Emit data.
   for (uptr P = Min; P != Max; ++P) {
-    // FIXME: Check that the address is readable before printing it.
     unsigned char C = *reinterpret_cast<const unsigned char*>(P);
     Printf("%s%02x", (P % 8 == 0) ? "  " : " ", C);
   }
   Printf("\n");
 
   // Emit highlights.
-  Printf(Decor.Green());
+  Printf(Decor.Highlight());
   Range *InRange = upperBound(Min, Ranges, NumRanges);
   for (uptr P = Min; P != Max; ++P) {
     char Pad = ' ', Byte = ' ';
@@ -225,7 +264,7 @@ static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
     char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
     Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
   }
-  Printf("%s\n", Decor.Default());
+  Printf("%s\n", Decor.EndHighlight());
 
   // Go over the line again, and print names for the ranges.
   InRange = 0;
@@ -263,8 +302,9 @@ static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
 }
 
 Diag::~Diag() {
-  __sanitizer::AnsiColorDecorator Decor(PrintsToTty());
-  SpinMutexLock l(&CommonSanitizerReportMutex);
+  // All diagnostics should be printed under report mutex.
+  CommonSanitizerReportMutex.CheckLocked();
+  Decorator Decor;
   Printf(Decor.Bold());
 
   renderLocation(Loc);
@@ -272,11 +312,11 @@ Diag::~Diag() {
   switch (Level) {
   case DL_Error:
     Printf("%s runtime error: %s%s",
-           Decor.Red(), Decor.Default(), Decor.Bold());
+           Decor.Warning(), Decor.EndWarning(), Decor.Bold());
     break;
 
   case DL_Note:
-    Printf("%s note: %s", Decor.Black(), Decor.Default());
+    Printf("%s note: %s", Decor.Note(), Decor.EndNote());
     break;
   }
 
@@ -288,3 +328,26 @@ Diag::~Diag() {
     renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
                         NumRanges, Args);
 }
+
+ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
+    : Opts(Opts), SummaryLoc(SummaryLoc) {
+  InitIfNecessary();
+  CommonSanitizerReportMutex.Lock();
+}
+
+ScopedReport::~ScopedReport() {
+  MaybePrintStackTrace(Opts.pc, Opts.bp);
+  MaybeReportErrorSummary(SummaryLoc);
+  CommonSanitizerReportMutex.Unlock();
+  if (Opts.DieAfterReport || flags()->halt_on_error)
+    Die();
+}
+
+bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) {
+  Suppression *s;
+  // If .preinit_array is not used, it is possible that the UBSan runtime is not
+  // initialized.
+  if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
+    InitIfNecessary();
+  return SuppressionContext::Get()->Match(Str, Type, &s);
+}