summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVedant Kumar <vsk@apple.com>2018-06-22 17:21:17 +0000
committerVedant Kumar <vsk@apple.com>2018-06-22 17:21:17 +0000
commit059d20360a1f872f15f063f89b784ba8352e4e09 (patch)
treec269a7f67a7449d12e060ccd798603d0e9c96413
parent22d1db122a921ed7608519d2461983ed687c5a87 (diff)
downloadbcm5719-llvm-059d20360a1f872f15f063f89b784ba8352e4e09.tar.gz
bcm5719-llvm-059d20360a1f872f15f063f89b784ba8352e4e09.zip
[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 llvm-svn: 335371
-rw-r--r--compiler-rt/lib/ubsan/CMakeLists.txt1
-rw-r--r--compiler-rt/lib/ubsan/ubsan_diag.cc8
-rw-r--r--compiler-rt/lib/ubsan/ubsan_diag.h20
-rw-r--r--compiler-rt/lib/ubsan/ubsan_handlers.cc90
-rw-r--r--compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc22
-rw-r--r--compiler-rt/lib/ubsan/ubsan_interface.inc2
-rw-r--r--compiler-rt/lib/ubsan/ubsan_monitor.cc76
-rw-r--r--compiler-rt/lib/ubsan/ubsan_monitor.h49
-rw-r--r--compiler-rt/test/ubsan/TestCases/Misc/monitor.cpp37
9 files changed, 246 insertions, 59 deletions
diff --git a/compiler-rt/lib/ubsan/CMakeLists.txt b/compiler-rt/lib/ubsan/CMakeLists.txt
index 20d6e291425..15bcbbef6af 100644
--- a/compiler-rt/lib/ubsan/CMakeLists.txt
+++ b/compiler-rt/lib/ubsan/CMakeLists.txt
@@ -5,6 +5,7 @@ set(UBSAN_SOURCES
ubsan_init.cc
ubsan_flags.cc
ubsan_handlers.cc
+ ubsan_monitor.cc
ubsan_value.cc
)
diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc
index d5b68407bb3..df4f13cbe2f 100644
--- a/compiler-rt/lib/ubsan/ubsan_diag.cc
+++ b/compiler-rt/lib/ubsan/ubsan_diag.cc
@@ -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(":");
diff --git a/compiler-rt/lib/ubsan/ubsan_diag.h b/compiler-rt/lib/ubsan/ubsan_diag.h
index 7370b1b6242..d9ea410c358 100644
--- a/compiler-rt/lib/ubsan/ubsan_diag.h
+++ b/compiler-rt/lib/ubsan/ubsan_diag.h
@@ -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) \
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cc b/compiler-rt/lib/ubsan/ubsan_handlers.cc
index bcda746a178..de2cc0ff216 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.cc
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.cc
@@ -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(TypeMismatchData *Data, ValueHandle Pointer,
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(TypeMismatchData *Data, ValueHandle Pointer,
}
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(OverflowData *Data, ValueHandle LHS,
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(OverflowData *Data, ValueHandle OldVal,
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(OverflowData *Data, ValueHandle LHS,
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(ShiftOutOfBoundsData *Data,
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(OutOfBoundsData *Data, ValueHandle Index,
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_bounds_abort(OutOfBoundsData *Data,
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_unreachable(UnreachableData *Data) {
}
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(VLABoundData *Data, ValueHandle Bound,
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 *DataPtr, ValueHandle From,
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(InvalidValueData *Data, ValueHandle Val,
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(InvalidBuiltinData *Data, ReportOptions Opts) {
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(FunctionTypeMismatchData *Data,
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(NonNullReturnData *Data, SourceLocation *LocPtr,
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(NonNullArgData *Data, ReportOptions Opts,
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(PointerOverflowData *Data,
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(CFICheckFailData *Data, ValueHandle Function,
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 {
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
index e15abc64ecc..3bc7fe4d18a 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
+++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc
@@ -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(CFICheckFailData *Data, ValueHandle Vtable,
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());
}
}
diff --git a/compiler-rt/lib/ubsan/ubsan_interface.inc b/compiler-rt/lib/ubsan/ubsan_interface.inc
index 9beb3e2ff95..ab00557f08c 100644
--- a/compiler-rt/lib/ubsan/ubsan_interface.inc
+++ b/compiler-rt/lib/ubsan/ubsan_interface.inc
@@ -52,3 +52,5 @@ INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1_abort)
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)
diff --git a/compiler-rt/lib/ubsan/ubsan_monitor.cc b/compiler-rt/lib/ubsan/ubsan_monitor.cc
new file mode 100644
index 00000000000..e2b39845ce3
--- /dev/null
+++ b/compiler-rt/lib/ubsan/ubsan_monitor.cc
@@ -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;
+}
diff --git a/compiler-rt/lib/ubsan/ubsan_monitor.h b/compiler-rt/lib/ubsan/ubsan_monitor.h
new file mode 100644
index 00000000000..7159cbb2c58
--- /dev/null
+++ b/compiler-rt/lib/ubsan/ubsan_monitor.h
@@ -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
diff --git a/compiler-rt/test/ubsan/TestCases/Misc/monitor.cpp b/compiler-rt/test/ubsan/TestCases/Misc/monitor.cpp
new file mode 100644
index 00000000000..78187019c0f
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/Misc/monitor.cpp
@@ -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;
+}
OpenPOWER on IntegriCloud