[compiler-rt] r335371 - [ubsan] Add support for reporting diagnostics to a monitor process

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 22 10:21:17 PDT 2018


Author: vedantk
Date: Fri Jun 22 10:21:17 2018
New Revision: 335371

URL: http://llvm.org/viewvc/llvm-project?rev=335371&view=rev
Log:
[ubsan] Add support for reporting diagnostics to a monitor process

Add support to the ubsan runtime for reporting diagnostics to a monitor
process (e.g a debugger).

The Xcode IDE uses this by setting a breakpoint on __ubsan_on_report and
collecting diagnostic information via __ubsan_get_current_report_data,
which it then surfaces to users in the editor UI.

Testing for this functionality already exists in upstream lldb, here:
lldb/packages/Python/lldbsuite/test/functionalities/ubsan

Apart from that, this is `ninja check-{a,ub}san` clean.

Differential Revision: https://reviews.llvm.org/D48446

Added:
    compiler-rt/trunk/lib/ubsan/ubsan_monitor.cc
    compiler-rt/trunk/lib/ubsan/ubsan_monitor.h
    compiler-rt/trunk/test/ubsan/TestCases/Misc/monitor.cpp
Modified:
    compiler-rt/trunk/lib/ubsan/CMakeLists.txt
    compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
    compiler-rt/trunk/lib/ubsan/ubsan_diag.h
    compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
    compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
    compiler-rt/trunk/lib/ubsan/ubsan_interface.inc

Modified: compiler-rt/trunk/lib/ubsan/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/CMakeLists.txt?rev=335371&r1=335370&r2=335371&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/CMakeLists.txt (original)
+++ compiler-rt/trunk/lib/ubsan/CMakeLists.txt Fri Jun 22 10:21:17 2018
@@ -5,6 +5,7 @@ set(UBSAN_SOURCES
   ubsan_init.cc
   ubsan_flags.cc
   ubsan_handlers.cc
+  ubsan_monitor.cc
   ubsan_value.cc
   )
 

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.cc?rev=335371&r1=335370&r2=335371&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.cc Fri Jun 22 10:21:17 2018
@@ -16,6 +16,7 @@
 #include "ubsan_diag.h"
 #include "ubsan_init.h"
 #include "ubsan_flags.h"
+#include "ubsan_monitor.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
@@ -340,6 +341,13 @@ Diag::~Diag() {
   Decorator Decor;
   InternalScopedString Buffer(1024);
 
+  // Prepare a report that a monitor process can inspect.
+  if (Level == DL_Error) {
+    RenderText(&Buffer, Message, Args);
+    UndefinedBehaviorReport UBR{ConvertTypeToString(ET), Loc, Buffer};
+    Buffer.clear();
+  }
+
   Buffer.append(Decor.Bold());
   RenderLocation(&Buffer, Loc);
   Buffer.append(":");

Modified: compiler-rt/trunk/lib/ubsan/ubsan_diag.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_diag.h?rev=335371&r1=335370&r2=335371&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_diag.h (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_diag.h Fri Jun 22 10:21:17 2018
@@ -121,6 +121,12 @@ public:
   const char *getName() const { return Name; }
 };
 
+enum class ErrorType {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+};
+
 /// \brief Representation of an in-flight diagnostic.
 ///
 /// Temporary \c Diag instances are created by the handler routines to
@@ -133,6 +139,9 @@ class Diag {
   /// The diagnostic level.
   DiagLevel Level;
 
+  /// The error type.
+  ErrorType ET;
+
   /// The message which will be emitted, with %0, %1, ... placeholders for
   /// arguments.
   const char *Message;
@@ -197,8 +206,9 @@ private:
   Diag &operator=(const Diag &);
 
 public:
-  Diag(Location Loc, DiagLevel Level, const char *Message)
-    : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
+  Diag(Location Loc, DiagLevel Level, ErrorType ET, const char *Message)
+      : Loc(Loc), Level(Level), ET(ET), Message(Message), NumArgs(0),
+        NumRanges(0) {}
   ~Diag();
 
   Diag &operator<<(const char *Str) { return AddArg(Str); }
@@ -219,12 +229,6 @@ struct ReportOptions {
   uptr bp;
 };
 
-enum class ErrorType {
-#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
-#include "ubsan_checks.inc"
-#undef UBSAN_CHECK
-};
-
 bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
 
 #define GET_REPORT_OPTIONS(unrecoverable_handler) \

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc?rev=335371&r1=335370&r2=335371&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc Fri Jun 22 10:21:17 2018
@@ -15,6 +15,7 @@
 #if CAN_SANITIZE_UB
 #include "ubsan_handlers.h"
 #include "ubsan_diag.h"
+#include "ubsan_monitor.h"
 
 #include "sanitizer_common/sanitizer_common.h"
 
@@ -70,17 +71,17 @@ static void handleTypeMismatchImpl(TypeM
 
   switch (ET) {
   case ErrorType::NullPointerUse:
-    Diag(Loc, DL_Error, "%0 null pointer of type %1")
+    Diag(Loc, DL_Error, ET, "%0 null pointer of type %1")
         << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
     break;
   case ErrorType::MisalignedPointerUse:
-    Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
+    Diag(Loc, DL_Error, ET, "%0 misaligned address %1 for type %3, "
                         "which requires %2 byte alignment")
         << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment
         << Data->Type;
     break;
   case ErrorType::InsufficientObjectSize:
-    Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
+    Diag(Loc, DL_Error, ET, "%0 address %1 with insufficient space "
                         "for an object of type %2")
         << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;
     break;
@@ -89,7 +90,7 @@ static void handleTypeMismatchImpl(TypeM
   }
 
   if (Pointer)
-    Diag(Pointer, DL_Note, "pointer points here");
+    Diag(Pointer, DL_Note, ET, "pointer points here");
 }
 
 void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data,
@@ -119,10 +120,10 @@ static void handleIntegerOverflowImpl(Ov
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error, "%0 integer overflow: "
-                      "%1 %2 %3 cannot be represented in type %4")
-    << (IsSigned ? "signed" : "unsigned")
-    << Value(Data->Type, LHS) << Operator << RHS << Data->Type;
+  Diag(Loc, DL_Error, ET, "%0 integer overflow: "
+                          "%1 %2 %3 cannot be represented in type %4")
+      << (IsSigned ? "signed" : "unsigned") << Value(Data->Type, LHS)
+      << Operator << RHS << Data->Type;
 }
 
 #define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable)                \
@@ -154,12 +155,12 @@ static void handleNegateOverflowImpl(Ove
   ScopedReport R(Opts, Loc, ET);
 
   if (IsSigned)
-    Diag(Loc, DL_Error,
+    Diag(Loc, DL_Error, ET,
          "negation of %0 cannot be represented in type %1; "
          "cast to an unsigned type to negate this value to itself")
         << Value(Data->Type, OldVal) << Data->Type;
   else
-    Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1")
+    Diag(Loc, DL_Error, ET, "negation of %0 cannot be represented in type %1")
         << Value(Data->Type, OldVal) << Data->Type;
 }
 
@@ -196,11 +197,12 @@ static void handleDivremOverflowImpl(Ove
 
   switch (ET) {
   case ErrorType::SignedIntegerOverflow:
-    Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1")
+    Diag(Loc, DL_Error, ET,
+         "division of %0 by -1 cannot be represented in type %1")
         << LHSVal << Data->Type;
     break;
   default:
-    Diag(Loc, DL_Error, "division by zero");
+    Diag(Loc, DL_Error, ET, "division by zero");
     break;
   }
 }
@@ -239,15 +241,16 @@ static void handleShiftOutOfBoundsImpl(S
 
   if (ET == ErrorType::InvalidShiftExponent) {
     if (RHSVal.isNegative())
-      Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
+      Diag(Loc, DL_Error, ET, "shift exponent %0 is negative") << RHSVal;
     else
-      Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2")
+      Diag(Loc, DL_Error, ET,
+           "shift exponent %0 is too large for %1-bit type %2")
           << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
   } else {
     if (LHSVal.isNegative())
-      Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
+      Diag(Loc, DL_Error, ET, "left shift of negative value %0") << LHSVal;
     else
-      Diag(Loc, DL_Error,
+      Diag(Loc, DL_Error, ET,
            "left shift of %0 by %1 places cannot be represented in type %2")
           << LHSVal << RHSVal << Data->LHSType;
   }
@@ -279,7 +282,7 @@ static void handleOutOfBoundsImpl(OutOfB
   ScopedReport R(Opts, Loc, ET);
 
   Value IndexVal(Data->IndexType, Index);
-  Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
+  Diag(Loc, DL_Error, ET, "index %0 out of bounds for type %1")
     << IndexVal << Data->ArrayType;
 }
 
@@ -297,8 +300,10 @@ void __ubsan::__ubsan_handle_out_of_boun
 
 static void handleBuiltinUnreachableImpl(UnreachableData *Data,
                                          ReportOptions Opts) {
-  ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall);
-  Diag(Data->Loc, DL_Error, "execution reached an unreachable program point");
+  ErrorType ET = ErrorType::UnreachableCall;
+  ScopedReport R(Opts, Data->Loc, ET);
+  Diag(Data->Loc, DL_Error, ET,
+       "execution reached an unreachable program point");
 }
 
 void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) {
@@ -308,8 +313,9 @@ void __ubsan::__ubsan_handle_builtin_unr
 }
 
 static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) {
-  ScopedReport R(Opts, Data->Loc, ErrorType::MissingReturn);
-  Diag(Data->Loc, DL_Error,
+  ErrorType ET = ErrorType::MissingReturn;
+  ScopedReport R(Opts, Data->Loc, ET);
+  Diag(Data->Loc, DL_Error, ET,
        "execution reached the end of a value-returning function "
        "without returning a value");
 }
@@ -330,9 +336,9 @@ static void handleVLABoundNotPositive(VL
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error, "variable length array bound evaluates to "
-                      "non-positive value %0")
-    << Value(Data->Type, Bound);
+  Diag(Loc, DL_Error, ET, "variable length array bound evaluates to "
+                          "non-positive value %0")
+      << Value(Data->Type, Bound);
 }
 
 void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data,
@@ -390,7 +396,7 @@ static void handleFloatCastOverflow(void
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error,
+  Diag(Loc, DL_Error, ET,
        "%0 is outside the range of representable values of type %2")
       << Value(*FromType, From) << *FromType << *ToType;
 }
@@ -421,9 +427,9 @@ static void handleLoadInvalidValue(Inval
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error,
+  Diag(Loc, DL_Error, ET,
        "load of value %0, which is not a valid value for type %1")
-    << Value(Data->Type, Val) << Data->Type;
+      << Value(Data->Type, Val) << Data->Type;
 }
 
 void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
@@ -447,7 +453,7 @@ static void handleInvalidBuiltin(Invalid
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error,
+  Diag(Loc, DL_Error, ET,
        "passing zero to %0, which is not a valid argument")
     << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
 }
@@ -478,10 +484,10 @@ static void handleFunctionTypeMismatch(F
   if (!FName)
     FName = "(unknown)";
 
-  Diag(CallLoc, DL_Error,
+  Diag(CallLoc, DL_Error, ET,
        "call to function %0 through pointer to incorrect function type %1")
       << FName << Data->Type;
-  Diag(FLoc, DL_Note, "%0 defined here") << FName;
+  Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
 }
 
 void
@@ -511,10 +517,10 @@ static void handleNonNullReturn(NonNullR
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error, "null pointer returned from function declared to never "
-                      "return null");
+  Diag(Loc, DL_Error, ET,
+       "null pointer returned from function declared to never return null");
   if (!Data->AttrLoc.isInvalid())
-    Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+    Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")
         << (IsAttr ? "returns_nonnull attribute"
                    : "_Nonnull return type annotation");
 }
@@ -555,12 +561,12 @@ static void handleNonNullArg(NonNullArgD
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error,
+  Diag(Loc, DL_Error, ET,
        "null pointer passed as argument %0, which is declared to "
        "never be null")
       << Data->ArgIndex;
   if (!Data->AttrLoc.isInvalid())
-    Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+    Diag(Data->AttrLoc, DL_Note, ET, "%0 specified here")
         << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");
 }
 
@@ -600,14 +606,15 @@ static void handlePointerOverflowImpl(Po
 
   if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {
     if (Base > Result)
-      Diag(Loc, DL_Error, "addition of unsigned offset to %0 overflowed to %1")
+      Diag(Loc, DL_Error, ET,
+           "addition of unsigned offset to %0 overflowed to %1")
           << (void *)Base << (void *)Result;
     else
-      Diag(Loc, DL_Error,
+      Diag(Loc, DL_Error, ET,
            "subtraction of unsigned offset from %0 overflowed to %1")
           << (void *)Base << (void *)Result;
   } else {
-    Diag(Loc, DL_Error,
+    Diag(Loc, DL_Error, ET,
          "pointer index expression with base %0 overflowed to %1")
         << (void *)Base << (void *)Result;
   }
@@ -641,15 +648,16 @@ static void handleCFIBadIcall(CFICheckFa
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
-                      "indirect function call")
+  Diag(Loc, DL_Error, ET,
+       "control flow integrity check for type %0 failed during "
+       "indirect function call")
       << Data->Type;
 
   SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
   const char *FName = FLoc.get()->info.function;
   if (!FName)
     FName = "(unknown)";
-  Diag(FLoc, DL_Note, "%0 defined here") << FName;
+  Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
 }
 
 namespace __ubsan {

Modified: compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc?rev=335371&r1=335370&r2=335371&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_handlers_cxx.cc Fri Jun 22 10:21:17 2018
@@ -50,29 +50,30 @@ static bool HandleDynamicTypeCacheMiss(
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error,
+  Diag(Loc, DL_Error, ET,
        "%0 address %1 which does not point to an object of type %2")
     << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
 
   // If possible, say what type it actually points to.
   if (!DTI.isValid()) {
     if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
-      Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big")
+      Diag(Pointer, DL_Note, ET,
+           "object has a possibly invalid vptr: abs(offset to top) too big")
           << TypeName(DTI.getMostDerivedTypeName())
           << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
     } else {
-      Diag(Pointer, DL_Note, "object has invalid vptr")
+      Diag(Pointer, DL_Note, ET, "object has invalid vptr")
           << TypeName(DTI.getMostDerivedTypeName())
           << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
     }
   } else if (!DTI.getOffset())
-    Diag(Pointer, DL_Note, "object is of type %0")
+    Diag(Pointer, DL_Note, ET, "object is of type %0")
         << TypeName(DTI.getMostDerivedTypeName())
         << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
   else
     // FIXME: Find the type at the specified offset, and include that
     //        in the note.
-    Diag(Pointer - DTI.getOffset(), DL_Note,
+    Diag(Pointer - DTI.getOffset(), DL_Note, ET,
          "object is base class subobject at offset %0 within object of type %1")
         << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName())
         << TypeName(DTI.getSubobjectTypeName())
@@ -126,19 +127,20 @@ void __ubsan_handle_cfi_bad_type(CFIChec
     Die();
   }
 
-  Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
-                      "%1 (vtable address %2)")
+  Diag(Loc, DL_Error, ET,
+       "control flow integrity check for type %0 failed during "
+       "%1 (vtable address %2)")
       << Data->Type << CheckKindStr << (void *)Vtable;
 
   // If possible, say what type it actually points to.
   if (!DTI.isValid()) {
     const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable);
     if (module)
-      Diag(Vtable, DL_Note, "invalid vtable in module %0") << module;
+      Diag(Vtable, DL_Note, ET, "invalid vtable in module %0") << module;
     else
-      Diag(Vtable, DL_Note, "invalid vtable");
+      Diag(Vtable, DL_Note, ET, "invalid vtable");
   } else {
-    Diag(Vtable, DL_Note, "vtable is of type %0")
+    Diag(Vtable, DL_Note, ET, "vtable is of type %0")
         << TypeName(DTI.getMostDerivedTypeName());
   }
 }

Modified: compiler-rt/trunk/lib/ubsan/ubsan_interface.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_interface.inc?rev=335371&r1=335370&r2=335371&view=diff
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_interface.inc (original)
+++ compiler-rt/trunk/lib/ubsan/ubsan_interface.inc Fri Jun 22 10:21:17 2018
@@ -52,3 +52,5 @@ INTERFACE_FUNCTION(__ubsan_handle_type_m
 INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive)
 INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive_abort)
 INTERFACE_WEAK_FUNCTION(__ubsan_default_options)
+INTERFACE_WEAK_FUNCTION(__ubsan_on_report)
+INTERFACE_FUNCTION(__ubsan_get_current_report_data)

Added: compiler-rt/trunk/lib/ubsan/ubsan_monitor.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_monitor.cc?rev=335371&view=auto
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_monitor.cc (added)
+++ compiler-rt/trunk/lib/ubsan/ubsan_monitor.cc Fri Jun 22 10:21:17 2018
@@ -0,0 +1,76 @@
+//===-- ubsan_monitor.cc ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Hooks which allow a monitor process to inspect UBSan's diagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_monitor.h"
+
+using namespace __ubsan;
+
+UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
+                                                 Location &Loc,
+                                                 InternalScopedString &Msg)
+    : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) {
+  // We have the common sanitizer reporting lock, so it's safe to register a
+  // new UB report.
+  RegisterUndefinedBehaviorReport(this);
+
+  // Make a copy of the diagnostic.
+  Buffer.append("%s", Msg.data());
+
+  // Let the monitor know that a report is available.
+  __ubsan_on_report();
+}
+
+static UndefinedBehaviorReport *CurrentUBR;
+
+void __ubsan::RegisterUndefinedBehaviorReport(UndefinedBehaviorReport *UBR) {
+  CurrentUBR = UBR;
+}
+
+SANITIZER_WEAK_DEFAULT_IMPL
+void __ubsan::__ubsan_on_report(void) {}
+
+void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
+                                              const char **OutMessage,
+                                              const char **OutFilename,
+                                              unsigned *OutLine,
+                                              unsigned *OutCol,
+                                              char **OutMemoryAddr) {
+  if (!OutIssueKind || !OutMessage || !OutFilename || !OutLine || !OutCol ||
+      !OutMemoryAddr)
+    UNREACHABLE("Invalid arguments passed to __ubsan_get_current_report_data");
+
+  InternalScopedString &Buf = CurrentUBR->Buffer;
+
+  // Ensure that the first character of the diagnostic text can't start with a
+  // lowercase letter.
+  char FirstChar = Buf.data()[0];
+  if (FirstChar >= 'a' && FirstChar <= 'z')
+    Buf.data()[0] = FirstChar - 'a' + 'A';
+
+  *OutIssueKind = CurrentUBR->IssueKind;
+  *OutMessage = Buf.data();
+  if (!CurrentUBR->Loc.isSourceLocation()) {
+    *OutFilename = "<unknown>";
+    *OutLine = *OutCol = 0;
+  } else {
+    SourceLocation SL = CurrentUBR->Loc.getSourceLocation();
+    *OutFilename = SL.getFilename();
+    *OutLine = SL.getLine();
+    *OutCol = SL.getColumn();
+  }
+
+  if (CurrentUBR->Loc.isMemoryLocation())
+    *OutMemoryAddr = (char *)CurrentUBR->Loc.getMemoryLocation();
+  else
+    *OutMemoryAddr = nullptr;
+}

Added: compiler-rt/trunk/lib/ubsan/ubsan_monitor.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/ubsan/ubsan_monitor.h?rev=335371&view=auto
==============================================================================
--- compiler-rt/trunk/lib/ubsan/ubsan_monitor.h (added)
+++ compiler-rt/trunk/lib/ubsan/ubsan_monitor.h Fri Jun 22 10:21:17 2018
@@ -0,0 +1,49 @@
+//===-- ubsan_monitor.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Hooks which allow a monitor process to inspect UBSan's diagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef UBSAN_MONITOR_H
+#define UBSAN_MONITOR_H
+
+#include "ubsan_diag.h"
+#include "ubsan_value.h"
+
+namespace __ubsan {
+
+struct UndefinedBehaviorReport {
+  const char *IssueKind;
+  Location &Loc;
+  InternalScopedString Buffer;
+
+  UndefinedBehaviorReport(const char *IssueKind, Location &Loc,
+                          InternalScopedString &Msg);
+};
+
+SANITIZER_INTERFACE_ATTRIBUTE void
+RegisterUndefinedBehaviorReport(UndefinedBehaviorReport *UBR);
+
+/// Called after a report is prepared. This serves to alert monitor processes
+/// that a UB report is available.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_on_report(void);
+
+/// Used by the monitor process to extract information from a UB report. The
+/// data is only available until the next time __ubsan_on_report is called. The
+/// caller is responsible for copying and preserving the data if needed.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
+__ubsan_get_current_report_data(const char **OutIssueKind,
+                                const char **OutMessage,
+                                const char **OutFilename, unsigned *OutLine,
+                                unsigned *OutCol, char **OutMemoryAddr);
+
+} // end namespace __ubsan
+
+#endif // UBSAN_MONITOR_H

Added: compiler-rt/trunk/test/ubsan/TestCases/Misc/monitor.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/ubsan/TestCases/Misc/monitor.cpp?rev=335371&view=auto
==============================================================================
--- compiler-rt/trunk/test/ubsan/TestCases/Misc/monitor.cpp (added)
+++ compiler-rt/trunk/test/ubsan/TestCases/Misc/monitor.cpp Fri Jun 22 10:21:17 2018
@@ -0,0 +1,37 @@
+// RUN: %clangxx -w -fsanitize=bool %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <iostream>
+
+extern "C" {
+void __ubsan_get_current_report_data(const char **OutIssueKind,
+                                     const char **OutMessage,
+                                     const char **OutFilename,
+                                     unsigned *OutLine, unsigned *OutCol,
+                                     char **OutMemoryAddr);
+
+// Override the weak definition of __ubsan_on_report from the runtime, just
+// for testing purposes.
+void __ubsan_on_report(void) {
+  const char *IssueKind, *Message, *Filename;
+  unsigned Line, Col;
+  char *Addr;
+  __ubsan_get_current_report_data(&IssueKind, &Message, &Filename, &Line, &Col,
+                                  &Addr);
+
+  std::cout << "Issue: " << IssueKind << "\n"
+            << "Location: " << Filename << ":" << Line << ":" << Col << "\n"
+            << "Message: " << Message << std::endl;
+
+  (void)Addr;
+}
+}
+
+int main() {
+  char C = 3;
+  bool B = *(bool *)&C;
+  // CHECK: Issue: invalid-bool-load
+  // CHECK-NEXT: Location: {{.*}}monitor.cpp:[[@LINE-2]]:12
+  // CHECK-NEXT: Message: Load of value 3, which is not a valid value for type 'bool'
+  return 0;
+}




More information about the llvm-commits mailing list