Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,196 @@
# Build for the undefined behavior sanitizer runtime support library.
set(UBSAN_SOURCES
ubsan_diag.cc
ubsan_init.cc
ubsan_flags.cc
ubsan_handlers.cc
ubsan_value.cc
)
set(UBSAN_STANDALONE_SOURCES
ubsan_diag_standalone.cc
ubsan_init_standalone.cc
ubsan_signals_standalone.cc
)
set(UBSAN_CXXABI_SOURCES
ubsan_handlers_cxx.cc
ubsan_type_hash.cc
ubsan_type_hash_itanium.cc
ubsan_type_hash_win.cc
)
include_directories(..)
set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_rtti_flag(OFF UBSAN_CFLAGS)
append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CFLAGS)
set(UBSAN_STANDALONE_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_rtti_flag(OFF UBSAN_STANDALONE_CFLAGS)
append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_STANDALONE_CFLAGS)
set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS})
append_rtti_flag(ON UBSAN_CXXFLAGS)
append_list_if(SANITIZER_CAN_USE_CXXABI -DUBSAN_CAN_USE_CXXABI UBSAN_CXXFLAGS)
set(UBSAN_DYNAMIC_LIBS ${SANITIZER_CXX_ABI_LIBRARY} ${SANITIZER_COMMON_LINK_LIBS})
append_list_if(COMPILER_RT_HAS_LIBDL dl UBSAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBLOG log UBSAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBRT rt UBSAN_DYNAMIC_LIBS)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread UBSAN_DYNAMIC_LIBS)
add_compiler_rt_component(ubsan)
if(APPLE)
set(UBSAN_COMMON_SOURCES ${UBSAN_SOURCES})
if(SANITIZER_CAN_USE_CXXABI)
list(APPEND UBSAN_COMMON_SOURCES ${UBSAN_CXXABI_SOURCES})
endif()
# Common parts of UBSan runtime.
add_compiler_rt_object_libraries(RTUbsan
OS ${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH}
SOURCES ${UBSAN_COMMON_SOURCES}
CFLAGS ${UBSAN_CXXFLAGS})
if(COMPILER_RT_HAS_UBSAN)
# Initializer of standalone UBSan runtime.
add_compiler_rt_object_libraries(RTUbsan_standalone
OS ${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_SUPPORTED_ARCH}
SOURCES ${UBSAN_STANDALONE_SOURCES}
CFLAGS ${UBSAN_STANDALONE_CFLAGS})
add_weak_symbols("ubsan" WEAK_SYMBOL_LINK_FLAGS)
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
add_compiler_rt_runtime(clang_rt.ubsan
SHARED
OS ${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTUbsan
RTUbsan_standalone
RTSanitizerCommon
RTSanitizerCommonLibc
RTInterception
LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
PARENT_TARGET ubsan)
add_compiler_rt_runtime(clang_rt.ubsan
STATIC
OS ${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTUbsan
RTUbsan_standalone
RTSanitizerCommonNoHooks
RTSanitizerCommonLibcNoHooks
RTInterception
LINK_FLAGS ${WEAK_SYMBOL_LINK_FLAGS}
PARENT_TARGET ubsan)
endif()
else()
# Common parts of UBSan runtime.
add_compiler_rt_object_libraries(RTUbsan
ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH}
SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS})
if(SANITIZER_CAN_USE_CXXABI)
# C++-specific parts of UBSan runtime. Requires a C++ ABI library.
set(UBSAN_CXX_SOURCES ${UBSAN_CXXABI_SOURCES})
else()
# Dummy target if we don't have C++ ABI library.
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cxx_dummy.cc "")
set(UBSAN_CXX_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/cxx_dummy.cc)
endif()
add_compiler_rt_object_libraries(RTUbsan_cxx
ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH}
SOURCES ${UBSAN_CXX_SOURCES} CFLAGS ${UBSAN_CXXFLAGS})
if (WIN32)
add_compiler_rt_object_libraries(UbsanWeakInterception
${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_SUPPORTED_ARCH}
SOURCES ubsan_win_weak_interception.cc
CFLAGS ${UBSAN_CFLAGS} -DSANITIZER_DYNAMIC
DEFS ${UBSAN_COMMON_DEFINITIONS})
add_compiler_rt_object_libraries(UbsanDllThunk
${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_SUPPORTED_ARCH}
SOURCES ubsan_win_dll_thunk.cc
CFLAGS ${UBSAN_CFLAGS} -DSANITIZER_DLL_THUNK
DEFS ${UBSAN_COMMON_DEFINITIONS})
set(DYNAMIC_RUNTIME_THUNK_CFLAGS "-DSANITIZER_DYNAMIC_RUNTIME_THUNK")
if(MSVC)
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-Zl")
elseif(CMAKE_C_COMPILER_ID MATCHES Clang)
list(APPEND DYNAMIC_RUNTIME_THUNK_CFLAGS "-nodefaultlibs")
endif()
add_compiler_rt_object_libraries(UbsanDynamicRuntimeThunk
${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${UBSAN_SUPPORTED_ARCH}
SOURCES ubsan_win_dynamic_runtime_thunk.cc
CFLAGS ${UBSAN_CFLAGS} ${DYNAMIC_RUNTIME_THUNK_CFLAGS}
DEFS ${UBSAN_COMMON_DEFINITIONS})
endif()
if(COMPILER_RT_HAS_UBSAN)
add_compiler_rt_object_libraries(RTUbsan_standalone
ARCHS ${UBSAN_SUPPORTED_ARCH}
SOURCES ${UBSAN_STANDALONE_SOURCES}
CFLAGS ${UBSAN_STANDALONE_CFLAGS})
# Standalone UBSan runtimes.
add_compiler_rt_runtime(clang_rt.ubsan_standalone
STATIC
ARCHS ${UBSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTSanitizerCommon
RTSanitizerCommonLibc
RTUbsan
RTUbsan_standalone
RTInterception
CFLAGS ${UBSAN_CFLAGS}
PARENT_TARGET ubsan)
add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx
STATIC
ARCHS ${UBSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTUbsan_cxx
CFLAGS ${UBSAN_CXXFLAGS}
PARENT_TARGET ubsan)
if (UNIX)
add_compiler_rt_runtime(clang_rt.ubsan_standalone
SHARED
ARCHS ${UBSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTSanitizerCommon
RTSanitizerCommonLibc
RTUbsan
RTUbsan_cxx
RTUbsan_standalone
RTInterception
CFLAGS ${UBSAN_CFLAGS}
LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}
LINK_LIBS ${UBSAN_DYNAMIC_LIBS}
PARENT_TARGET ubsan)
set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH})
list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386)
add_sanitizer_rt_symbols(clang_rt.ubsan_standalone
ARCHS ${ARCHS_FOR_SYMBOLS}
PARENT_TARGET ubsan
EXTRA ubsan.syms.extra)
add_sanitizer_rt_symbols(clang_rt.ubsan_standalone_cxx
ARCHS ${ARCHS_FOR_SYMBOLS}
PARENT_TARGET ubsan
EXTRA ubsan.syms.extra)
endif()
endif()
endif()

View File

@@ -0,0 +1 @@
__ubsan_*

View File

@@ -0,0 +1,47 @@
//===-- ubsan_checks.inc ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// List of checks handled by UBSan runtime.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_CHECK
# error "Define UBSAN_CHECK prior to including this file!"
#endif
// UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName)
// SummaryKind and FSanitizeFlagName should be string literals.
UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow")
UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size")
UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow",
"signed-integer-overflow")
UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow",
"unsigned-integer-overflow")
UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
"integer-divide-by-zero")
UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero")
UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use")
UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base")
UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent")
UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
UBSAN_CHECK(UnreachableCall, "unreachable-call", "unreachable")
UBSAN_CHECK(MissingReturn, "missing-return", "return")
UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index", "vla-bound")
UBSAN_CHECK(FloatCastOverflow, "float-cast-overflow", "float-cast-overflow")
UBSAN_CHECK(InvalidBoolLoad, "invalid-bool-load", "bool")
UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function")
UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
"returns-nonnull-attribute")
UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute")
UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")

View File

@@ -0,0 +1,428 @@
//===-- ubsan_diag.cc -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Diagnostic reporting for the UBSan runtime.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
#include "ubsan_diag.h"
#include "ubsan_init.h"
#include "ubsan_flags.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_stacktrace_printer.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
#include <stdio.h>
using namespace __ubsan;
void __ubsan::GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc,
uptr bp, void *context, bool fast) {
uptr top = 0;
uptr bottom = 0;
if (fast)
GetThreadStackTopAndBottom(false, &top, &bottom);
stack->Unwind(max_depth, pc, bp, context, top, bottom, fast);
}
static void MaybePrintStackTrace(uptr pc, uptr bp) {
// We assume that flags are already parsed, as UBSan runtime
// will definitely be called when we print the first diagnostics message.
if (!flags()->print_stacktrace)
return;
BufferedStackTrace stack;
GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr,
common_flags()->fast_unwind_on_fatal);
stack.Print();
}
static const char *ConvertTypeToString(ErrorType Type) {
switch (Type) {
#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
case ErrorType::Name: \
return SummaryKind;
#include "ubsan_checks.inc"
#undef UBSAN_CHECK
}
UNREACHABLE("unknown ErrorType!");
}
static const char *ConvertTypeToFlagName(ErrorType Type) {
switch (Type) {
#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
case ErrorType::Name: \
return FSanitizeFlagName;
#include "ubsan_checks.inc"
#undef UBSAN_CHECK
}
UNREACHABLE("unknown ErrorType!");
}
static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
if (!common_flags()->print_summary)
return;
if (!flags()->report_error_type)
Type = ErrorType::GenericUB;
const char *ErrorKind = ConvertTypeToString(Type);
if (Loc.isSourceLocation()) {
SourceLocation SLoc = Loc.getSourceLocation();
if (!SLoc.isInvalid()) {
AddressInfo AI;
AI.file = internal_strdup(SLoc.getFilename());
AI.line = SLoc.getLine();
AI.column = SLoc.getColumn();
AI.function = internal_strdup(""); // Avoid printing ?? as function name.
ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
AI.Clear();
return;
}
} else if (Loc.isSymbolizedStack()) {
const AddressInfo &AI = Loc.getSymbolizedStack()->info;
ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
return;
}
ReportErrorSummary(ErrorKind, GetSanititizerToolName());
}
namespace {
class Decorator : public SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() {}
const char *Highlight() const { return Green(); }
const char *Note() const { return Black(); }
};
}
SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) {
InitAsStandaloneIfNecessary();
return Symbolizer::GetOrInit()->SymbolizePC(PC);
}
Diag &Diag::operator<<(const TypeDescriptor &V) {
return AddArg(V.getTypeName());
}
Diag &Diag::operator<<(const Value &V) {
if (V.getType().isSignedIntegerTy())
AddArg(V.getSIntValue());
else if (V.getType().isUnsignedIntegerTy())
AddArg(V.getUIntValue());
else if (V.getType().isFloatTy())
AddArg(V.getFloatValue());
else
AddArg("<unknown>");
return *this;
}
/// Hexadecimal printing for numbers too large for Printf to handle directly.
static void RenderHex(InternalScopedString *Buffer, UIntMax Val) {
#if HAVE_INT128_T
Buffer->append("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96),
(unsigned int)(Val >> 64), (unsigned int)(Val >> 32),
(unsigned int)(Val));
#else
UNREACHABLE("long long smaller than 64 bits?");
#endif
}
static void RenderLocation(InternalScopedString *Buffer, Location Loc) {
switch (Loc.getKind()) {
case Location::LK_Source: {
SourceLocation SLoc = Loc.getSourceLocation();
if (SLoc.isInvalid())
Buffer->append("<unknown>");
else
RenderSourceLocation(Buffer, SLoc.getFilename(), SLoc.getLine(),
SLoc.getColumn(), common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
return;
}
case Location::LK_Memory:
Buffer->append("%p", Loc.getMemoryLocation());
return;
case Location::LK_Symbolized: {
const AddressInfo &Info = Loc.getSymbolizedStack()->info;
if (Info.file)
RenderSourceLocation(Buffer, Info.file, Info.line, Info.column,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
else if (Info.module)
RenderModuleLocation(Buffer, Info.module, Info.module_offset,
Info.module_arch, common_flags()->strip_path_prefix);
else
Buffer->append("%p", Info.address);
return;
}
case Location::LK_Null:
Buffer->append("<unknown>");
return;
}
}
static void RenderText(InternalScopedString *Buffer, const char *Message,
const Diag::Arg *Args) {
for (const char *Msg = Message; *Msg; ++Msg) {
if (*Msg != '%') {
Buffer->append("%c", *Msg);
continue;
}
const Diag::Arg &A = Args[*++Msg - '0'];
switch (A.Kind) {
case Diag::AK_String:
Buffer->append("%s", A.String);
break;
case Diag::AK_TypeName: {
if (SANITIZER_WINDOWS)
// The Windows implementation demangles names early.
Buffer->append("'%s'", A.String);
else
Buffer->append("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
break;
}
case Diag::AK_SInt:
// 'long long' is guaranteed to be at least 64 bits wide.
if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
Buffer->append("%lld", (long long)A.SInt);
else
RenderHex(Buffer, A.SInt);
break;
case Diag::AK_UInt:
if (A.UInt <= UINT64_MAX)
Buffer->append("%llu", (unsigned long long)A.UInt);
else
RenderHex(Buffer, A.UInt);
break;
case Diag::AK_Float: {
// FIXME: Support floating-point formatting in sanitizer_common's
// printf, and stop using snprintf here.
char FloatBuffer[32];
#if SANITIZER_WINDOWS
sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
#else
snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
#endif
Buffer->append("%s", FloatBuffer);
break;
}
case Diag::AK_Pointer:
Buffer->append("%p", A.Pointer);
break;
}
}
}
/// Find the earliest-starting range in Ranges which ends after Loc.
static Range *upperBound(MemoryLocation Loc, Range *Ranges,
unsigned NumRanges) {
Range *Best = 0;
for (unsigned I = 0; I != NumRanges; ++I)
if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
(!Best ||
Best->getStart().getMemoryLocation() >
Ranges[I].getStart().getMemoryLocation()))
Best = &Ranges[I];
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 PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
Range *Ranges, unsigned NumRanges,
const Diag::Arg *Args) {
// Show at least the 8 bytes surrounding Loc.
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, OrigMin);
Max = addNoOverflow(Min, BytesToShow);
if (!IsAccessibleMemoryRange(Min, Max - Min)) {
Printf("<memory cannot be printed>\n");
return;
}
// Emit data.
InternalScopedString Buffer(1024);
for (uptr P = Min; P != Max; ++P) {
unsigned char C = *reinterpret_cast<const unsigned char*>(P);
Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C);
}
Buffer.append("\n");
// Emit highlights.
Buffer.append(Decor.Highlight());
Range *InRange = upperBound(Min, Ranges, NumRanges);
for (uptr P = Min; P != Max; ++P) {
char Pad = ' ', Byte = ' ';
if (InRange && InRange->getEnd().getMemoryLocation() == P)
InRange = upperBound(P, Ranges, NumRanges);
if (!InRange && P > Loc)
break;
if (InRange && InRange->getStart().getMemoryLocation() < P)
Pad = '~';
if (InRange && InRange->getStart().getMemoryLocation() <= P)
Byte = '~';
if (P % 8 == 0)
Buffer.append("%c", Pad);
Buffer.append("%c", Pad);
Buffer.append("%c", P == Loc ? '^' : Byte);
Buffer.append("%c", Byte);
}
Buffer.append("%s\n", Decor.Default());
// Go over the line again, and print names for the ranges.
InRange = 0;
unsigned Spaces = 0;
for (uptr P = Min; P != Max; ++P) {
if (!InRange || InRange->getEnd().getMemoryLocation() == P)
InRange = upperBound(P, Ranges, NumRanges);
if (!InRange)
break;
Spaces += (P % 8) == 0 ? 2 : 1;
if (InRange && InRange->getStart().getMemoryLocation() == P) {
while (Spaces--)
Buffer.append(" ");
RenderText(&Buffer, InRange->getText(), Args);
Buffer.append("\n");
// FIXME: We only support naming one range for now!
break;
}
Spaces += 2;
}
Printf("%s", Buffer.data());
// FIXME: Print names for anything we can identify within the line:
//
// * If we can identify the memory itself as belonging to a particular
// global, stack variable, or dynamic allocation, then do so.
//
// * If we have a pointer-size, pointer-aligned range highlighted,
// determine whether the value of that range is a pointer to an
// entity which we can name, and if so, print that name.
//
// This needs an external symbolizer, or (preferably) ASan instrumentation.
}
Diag::~Diag() {
// All diagnostics should be printed under report mutex.
ScopedReport::CheckLocked();
Decorator Decor;
InternalScopedString Buffer(1024);
Buffer.append(Decor.Bold());
RenderLocation(&Buffer, Loc);
Buffer.append(":");
switch (Level) {
case DL_Error:
Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.Default(),
Decor.Bold());
break;
case DL_Note:
Buffer.append("%s note: %s", Decor.Note(), Decor.Default());
break;
}
RenderText(&Buffer, Message, Args);
Buffer.append("%s\n", Decor.Default());
Printf("%s", Buffer.data());
if (Loc.isMemoryLocation())
PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args);
}
ScopedReport::Initializer::Initializer() { InitAsStandaloneIfNecessary(); }
ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
ErrorType Type)
: Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {}
ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
MaybeReportErrorSummary(SummaryLoc, Type);
if (flags()->halt_on_error)
Die();
}
ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kVptrCheck[] = "vptr_check";
static const char *kSuppressionTypes[] = {
#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName,
#include "ubsan_checks.inc"
#undef UBSAN_CHECK
kVptrCheck,
};
void __ubsan::InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
suppression_ctx = new (suppression_placeholder) // NOLINT
SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
suppression_ctx->ParseFromFile(flags()->suppressions);
}
bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
InitAsStandaloneIfNecessary();
CHECK(suppression_ctx);
Suppression *s;
return suppression_ctx->Match(TypeName, kVptrCheck, &s);
}
bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) {
InitAsStandaloneIfNecessary();
CHECK(suppression_ctx);
const char *SuppType = ConvertTypeToFlagName(ET);
// Fast path: don't symbolize PC if there is no suppressions for given UB
// type.
if (!suppression_ctx->HasSuppressionType(SuppType))
return false;
Suppression *s = nullptr;
// Suppress by file name known to runtime.
if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s))
return true;
// Suppress by module name.
if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) {
if (suppression_ctx->Match(Module, SuppType, &s))
return true;
}
// Suppress by function or source file name from debug info.
SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC));
const AddressInfo &AI = Stack.get()->info;
return suppression_ctx->Match(AI.function, SuppType, &s) ||
suppression_ctx->Match(AI.file, SuppType, &s);
}
#endif // CAN_SANITIZE_UB

View File

@@ -0,0 +1,266 @@
//===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Diagnostics emission for Clang's undefined behavior sanitizer.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_DIAG_H
#define UBSAN_DIAG_H
#include "ubsan_value.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
namespace __ubsan {
class SymbolizedStackHolder {
SymbolizedStack *Stack;
void clear() {
if (Stack)
Stack->ClearAll();
}
public:
explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
: Stack(Stack) {}
~SymbolizedStackHolder() { clear(); }
void reset(SymbolizedStack *S) {
if (Stack != S)
clear();
Stack = S;
}
const SymbolizedStack *get() const { return Stack; }
};
SymbolizedStack *getSymbolizedLocation(uptr PC);
inline SymbolizedStack *getCallerLocation(uptr CallerPC) {
CHECK(CallerPC);
uptr PC = StackTrace::GetPreviousInstructionPc(CallerPC);
return getSymbolizedLocation(PC);
}
/// A location of some data within the program's address space.
typedef uptr MemoryLocation;
/// \brief Location at which a diagnostic can be emitted. Either a
/// SourceLocation, a MemoryLocation, or a SymbolizedStack.
class Location {
public:
enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized };
private:
LocationKind Kind;
// FIXME: In C++11, wrap these in an anonymous union.
SourceLocation SourceLoc;
MemoryLocation MemoryLoc;
const SymbolizedStack *SymbolizedLoc; // Not owned.
public:
Location() : Kind(LK_Null) {}
Location(SourceLocation Loc) :
Kind(LK_Source), SourceLoc(Loc) {}
Location(MemoryLocation Loc) :
Kind(LK_Memory), MemoryLoc(Loc) {}
// SymbolizedStackHolder must outlive Location object.
Location(const SymbolizedStackHolder &Stack) :
Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {}
LocationKind getKind() const { return Kind; }
bool isSourceLocation() const { return Kind == LK_Source; }
bool isMemoryLocation() const { return Kind == LK_Memory; }
bool isSymbolizedStack() const { return Kind == LK_Symbolized; }
SourceLocation getSourceLocation() const {
CHECK(isSourceLocation());
return SourceLoc;
}
MemoryLocation getMemoryLocation() const {
CHECK(isMemoryLocation());
return MemoryLoc;
}
const SymbolizedStack *getSymbolizedStack() const {
CHECK(isSymbolizedStack());
return SymbolizedLoc;
}
};
/// A diagnostic severity level.
enum DiagLevel {
DL_Error, ///< An error.
DL_Note ///< A note, attached to a prior diagnostic.
};
/// \brief Annotation for a range of locations in a diagnostic.
class Range {
Location Start, End;
const char *Text;
public:
Range() : Start(), End(), Text() {}
Range(MemoryLocation Start, MemoryLocation End, const char *Text)
: Start(Start), End(End), Text(Text) {}
Location getStart() const { return Start; }
Location getEnd() const { return End; }
const char *getText() const { return Text; }
};
/// \brief A C++ type name. Really just a strong typedef for 'const char*'.
class TypeName {
const char *Name;
public:
TypeName(const char *Name) : Name(Name) {}
const char *getName() const { return Name; }
};
/// \brief Representation of an in-flight diagnostic.
///
/// Temporary \c Diag instances are created by the handler routines to
/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
/// message.
class Diag {
/// The location at which the problem occurred.
Location Loc;
/// The diagnostic level.
DiagLevel Level;
/// The message which will be emitted, with %0, %1, ... placeholders for
/// arguments.
const char *Message;
public:
/// Kinds of arguments, corresponding to members of \c Arg's union.
enum ArgKind {
AK_String, ///< A string argument, displayed as-is.
AK_TypeName,///< A C++ type name, possibly demangled before display.
AK_UInt, ///< An unsigned integer argument.
AK_SInt, ///< A signed integer argument.
AK_Float, ///< A floating-point argument.
AK_Pointer ///< A pointer argument, displayed in hexadecimal.
};
/// An individual diagnostic message argument.
struct Arg {
Arg() {}
Arg(const char *String) : Kind(AK_String), String(String) {}
Arg(TypeName TN) : Kind(AK_TypeName), String(TN.getName()) {}
Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
ArgKind Kind;
union {
const char *String;
UIntMax UInt;
SIntMax SInt;
FloatMax Float;
const void *Pointer;
};
};
private:
static const unsigned MaxArgs = 5;
static const unsigned MaxRanges = 1;
/// The arguments which have been added to this diagnostic so far.
Arg Args[MaxArgs];
unsigned NumArgs;
/// The ranges which have been added to this diagnostic so far.
Range Ranges[MaxRanges];
unsigned NumRanges;
Diag &AddArg(Arg A) {
CHECK(NumArgs != MaxArgs);
Args[NumArgs++] = A;
return *this;
}
Diag &AddRange(Range A) {
CHECK(NumRanges != MaxRanges);
Ranges[NumRanges++] = A;
return *this;
}
/// \c Diag objects are not copyable.
Diag(const Diag &); // NOT IMPLEMENTED
Diag &operator=(const Diag &);
public:
Diag(Location Loc, DiagLevel Level, const char *Message)
: Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
~Diag();
Diag &operator<<(const char *Str) { return AddArg(Str); }
Diag &operator<<(TypeName TN) { return AddArg(TN); }
Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
Diag &operator<<(const void *V) { return AddArg(V); }
Diag &operator<<(const TypeDescriptor &V);
Diag &operator<<(const Value &V);
Diag &operator<<(const Range &R) { return AddRange(R); }
};
struct ReportOptions {
// If FromUnrecoverableHandler is specified, UBSan runtime handler is not
// expected to return.
bool FromUnrecoverableHandler;
/// pc/bp are used to unwind the stack trace.
uptr pc;
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) \
GET_CALLER_PC_BP; \
ReportOptions Opts = {unrecoverable_handler, pc, bp}
void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp,
void *context, bool fast);
/// \brief Instantiate this class before printing diagnostics in the error
/// report. This class ensures that reports from different threads and from
/// different sanitizers won't be mixed.
class ScopedReport {
struct Initializer {
Initializer();
};
Initializer initializer_;
ScopedErrorReportLock report_lock_;
ReportOptions Opts;
Location SummaryLoc;
ErrorType Type;
public:
ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
~ScopedReport();
static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
};
void InitializeSuppressions();
bool IsVptrCheckSuppressed(const char *TypeName);
// Sometimes UBSan runtime can know filename from handlers arguments, even if
// debug info is missing.
bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
} // namespace __ubsan
#endif // UBSAN_DIAG_H

View File

@@ -0,0 +1,38 @@
//===-- ubsan_diag_standalone.cc ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Diagnostic reporting for the standalone UBSan runtime.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
#include "ubsan_diag.h"
using namespace __ubsan;
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_print_stack_trace() {
uptr top = 0;
uptr bottom = 0;
bool request_fast_unwind = common_flags()->fast_unwind_on_fatal;
if (request_fast_unwind)
__sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom);
GET_CURRENT_PC_BP_SP;
(void)sp;
BufferedStackTrace stack;
stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom,
request_fast_unwind);
stack.Print();
}
} // extern "C"
#endif // CAN_SANITIZE_UB

View File

@@ -0,0 +1,77 @@
//===-- ubsan_flags.cc ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Runtime flags for UndefinedBehaviorSanitizer.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
#include "ubsan_flags.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include <stdlib.h>
namespace __ubsan {
const char *MaybeCallUbsanDefaultOptions() {
return (&__ubsan_default_options) ? __ubsan_default_options() : "";
}
Flags ubsan_flags;
void Flags::SetDefaults() {
#define UBSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "ubsan_flags.inc"
#undef UBSAN_FLAG
}
void RegisterUbsanFlags(FlagParser *parser, Flags *f) {
#define UBSAN_FLAG(Type, Name, DefaultValue, Description) \
RegisterFlag(parser, #Name, Description, &f->Name);
#include "ubsan_flags.inc"
#undef UBSAN_FLAG
}
void InitializeFlags() {
SetCommonFlagsDefaults();
{
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.print_summary = false;
cf.external_symbolizer_path = getenv("UBSAN_SYMBOLIZER_PATH");
OverrideCommonFlags(cf);
}
Flags *f = flags();
f->SetDefaults();
FlagParser parser;
RegisterCommonFlags(&parser);
RegisterUbsanFlags(&parser, f);
// Override from user-specified string.
parser.ParseString(MaybeCallUbsanDefaultOptions());
// Override from environment variable.
parser.ParseString(getenv("UBSAN_OPTIONS"));
InitializeCommonFlags();
if (Verbosity()) ReportUnrecognizedFlags();
if (common_flags()->help) parser.PrintFlagDescriptions();
}
} // namespace __ubsan
SANITIZER_INTERFACE_WEAK_DEF(const char *, __ubsan_default_options, void) {
return "";
}
#endif // CAN_SANITIZE_UB

View File

@@ -0,0 +1,49 @@
//===-- ubsan_flags.h -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Runtime flags for UndefinedBehaviorSanitizer.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_FLAGS_H
#define UBSAN_FLAGS_H
#include "sanitizer_common/sanitizer_internal_defs.h"
namespace __sanitizer {
class FlagParser;
}
namespace __ubsan {
struct Flags {
#define UBSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
#include "ubsan_flags.inc"
#undef UBSAN_FLAG
void SetDefaults();
};
extern Flags ubsan_flags;
inline Flags *flags() { return &ubsan_flags; }
void InitializeFlags();
void RegisterUbsanFlags(FlagParser *parser, Flags *f);
const char *MaybeCallUbsanDefaultOptions();
} // namespace __ubsan
extern "C" {
// Users may provide their own implementation of __ubsan_default_options to
// override the default flag values.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char *__ubsan_default_options();
} // extern "C"
#endif // UBSAN_FLAGS_H

View File

@@ -0,0 +1,26 @@
//===-- ubsan_flags.inc -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// UBSan runtime flags.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_FLAG
# error "Define UBSAN_FLAG prior to including this file!"
#endif
// UBSAN_FLAG(Type, Name, DefaultValue, Description)
// See COMMON_FLAG in sanitizer_flags.inc for more details.
UBSAN_FLAG(bool, halt_on_error, false,
"Crash the program after printing the first error report")
UBSAN_FLAG(bool, print_stacktrace, false,
"Include full stacktrace into an error report")
UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
UBSAN_FLAG(bool, report_error_type, false,
"Print specific error type instead of 'undefined-behavior' in summary.")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
//===-- ubsan_handlers.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Entry points to the runtime library for Clang's undefined behavior sanitizer.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_HANDLERS_H
#define UBSAN_HANDLERS_H
#include "ubsan_value.h"
namespace __ubsan {
struct TypeMismatchData {
SourceLocation Loc;
const TypeDescriptor &Type;
unsigned char LogAlignment;
unsigned char TypeCheckKind;
};
#define UNRECOVERABLE(checkname, ...) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
void __ubsan_handle_ ## checkname( __VA_ARGS__ );
#define RECOVERABLE(checkname, ...) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE \
void __ubsan_handle_ ## checkname( __VA_ARGS__ ); \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE NORETURN \
void __ubsan_handle_ ## checkname ## _abort( __VA_ARGS__ );
/// \brief Handle a runtime type check failure, caused by either a misaligned
/// pointer, a null pointer, or a pointer to insufficient storage for the
/// type.
RECOVERABLE(type_mismatch_v1, TypeMismatchData *Data, ValueHandle Pointer)
struct OverflowData {
SourceLocation Loc;
const TypeDescriptor &Type;
};
/// \brief Handle an integer addition overflow.
RECOVERABLE(add_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
/// \brief Handle an integer subtraction overflow.
RECOVERABLE(sub_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
/// \brief Handle an integer multiplication overflow.
RECOVERABLE(mul_overflow, OverflowData *Data, ValueHandle LHS, ValueHandle RHS)
/// \brief Handle a signed integer overflow for a unary negate operator.
RECOVERABLE(negate_overflow, OverflowData *Data, ValueHandle OldVal)
/// \brief Handle an INT_MIN/-1 overflow or division by zero.
RECOVERABLE(divrem_overflow, OverflowData *Data,
ValueHandle LHS, ValueHandle RHS)
struct ShiftOutOfBoundsData {
SourceLocation Loc;
const TypeDescriptor &LHSType;
const TypeDescriptor &RHSType;
};
/// \brief Handle a shift where the RHS is out of bounds or a left shift where
/// the LHS is negative or overflows.
RECOVERABLE(shift_out_of_bounds, ShiftOutOfBoundsData *Data,
ValueHandle LHS, ValueHandle RHS)
struct OutOfBoundsData {
SourceLocation Loc;
const TypeDescriptor &ArrayType;
const TypeDescriptor &IndexType;
};
/// \brief Handle an array index out of bounds error.
RECOVERABLE(out_of_bounds, OutOfBoundsData *Data, ValueHandle Index)
struct UnreachableData {
SourceLocation Loc;
};
/// \brief Handle a __builtin_unreachable which is reached.
UNRECOVERABLE(builtin_unreachable, UnreachableData *Data)
/// \brief Handle reaching the end of a value-returning function.
UNRECOVERABLE(missing_return, UnreachableData *Data)
struct VLABoundData {
SourceLocation Loc;
const TypeDescriptor &Type;
};
/// \brief Handle a VLA with a non-positive bound.
RECOVERABLE(vla_bound_not_positive, VLABoundData *Data, ValueHandle Bound)
// Keeping this around for binary compatibility with (sanitized) programs
// compiled with older compilers.
struct FloatCastOverflowData {
const TypeDescriptor &FromType;
const TypeDescriptor &ToType;
};
struct FloatCastOverflowDataV2 {
SourceLocation Loc;
const TypeDescriptor &FromType;
const TypeDescriptor &ToType;
};
/// Handle overflow in a conversion to or from a floating-point type.
/// void *Data is one of FloatCastOverflowData* or FloatCastOverflowDataV2*
RECOVERABLE(float_cast_overflow, void *Data, ValueHandle From)
struct InvalidValueData {
SourceLocation Loc;
const TypeDescriptor &Type;
};
/// \brief Handle a load of an invalid value for the type.
RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
/// Known builtin check kinds.
/// Keep in sync with the enum of the same name in CodeGenFunction.h
enum BuiltinCheckKind : unsigned char {
BCK_CTZPassedZero,
BCK_CLZPassedZero,
};
struct InvalidBuiltinData {
SourceLocation Loc;
unsigned char Kind;
};
/// Handle a builtin called in an invalid way.
RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data)
struct FunctionTypeMismatchData {
SourceLocation Loc;
const TypeDescriptor &Type;
};
RECOVERABLE(function_type_mismatch,
FunctionTypeMismatchData *Data,
ValueHandle Val)
struct NonNullReturnData {
SourceLocation AttrLoc;
};
/// \brief Handle returning null from function with the returns_nonnull
/// attribute, or a return type annotated with _Nonnull.
RECOVERABLE(nonnull_return_v1, NonNullReturnData *Data, SourceLocation *Loc)
RECOVERABLE(nullability_return_v1, NonNullReturnData *Data, SourceLocation *Loc)
struct NonNullArgData {
SourceLocation Loc;
SourceLocation AttrLoc;
int ArgIndex;
};
/// \brief Handle passing null pointer to a function parameter with the nonnull
/// attribute, or a _Nonnull type annotation.
RECOVERABLE(nonnull_arg, NonNullArgData *Data)
RECOVERABLE(nullability_arg, NonNullArgData *Data)
struct PointerOverflowData {
SourceLocation Loc;
};
RECOVERABLE(pointer_overflow, PointerOverflowData *Data, ValueHandle Base,
ValueHandle Result)
/// \brief Known CFI check kinds.
/// Keep in sync with the enum of the same name in CodeGenFunction.h
enum CFITypeCheckKind : unsigned char {
CFITCK_VCall,
CFITCK_NVCall,
CFITCK_DerivedCast,
CFITCK_UnrelatedCast,
CFITCK_ICall,
};
struct CFICheckFailData {
CFITypeCheckKind CheckKind;
SourceLocation Loc;
const TypeDescriptor &Type;
};
/// \brief Handle control flow integrity failures.
RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
uptr VtableIsValid)
struct ReportOptions;
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_handle_cfi_bad_type(
CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable,
ReportOptions Opts);
}
#endif // UBSAN_HANDLERS_H

View File

@@ -0,0 +1,147 @@
//===-- ubsan_handlers_cxx.cc ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Error logging entry points for the UBSan runtime, which are only used for C++
// compilations. This file is permitted to use language features which require
// linking against a C++ ABI library.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
#include "ubsan_handlers.h"
#include "ubsan_handlers_cxx.h"
#include "ubsan_diag.h"
#include "ubsan_type_hash.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_suppressions.h"
using namespace __sanitizer;
using namespace __ubsan;
namespace __ubsan {
extern const char *TypeCheckKinds[];
}
// Returns true if UBSan has printed an error report.
static bool HandleDynamicTypeCacheMiss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
ReportOptions Opts) {
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
// Just a cache miss. The type matches after all.
return false;
// Check if error report should be suppressed.
DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer);
if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
return false;
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::DynamicTypeMismatch;
if (ignoreReport(Loc, Opts, ET))
return false;
ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"%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")
<< TypeName(DTI.getMostDerivedTypeName())
<< Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
} else {
Diag(Pointer, DL_Note, "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")
<< 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,
"object is base class subobject at offset %0 within object of type %1")
<< DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName())
<< TypeName(DTI.getSubobjectTypeName())
<< Range(Pointer, Pointer + sizeof(uptr),
"vptr for %2 base class of %1");
return true;
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
GET_REPORT_OPTIONS(false);
HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
// Note: -fsanitize=vptr is always recoverable.
GET_REPORT_OPTIONS(false);
if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts))
Die();
}
namespace __ubsan {
void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
bool ValidVtable, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::CFIBadType;
if (ignoreReport(Loc, Opts, ET))
return;
ScopedReport R(Opts, Loc, ET);
DynamicTypeInfo DTI = ValidVtable
? getDynamicTypeInfoFromVtable((void *)Vtable)
: DynamicTypeInfo(0, 0, 0);
const char *CheckKindStr;
switch (Data->CheckKind) {
case CFITCK_VCall:
CheckKindStr = "virtual call";
break;
case CFITCK_NVCall:
CheckKindStr = "non-virtual call";
break;
case CFITCK_DerivedCast:
CheckKindStr = "base-to-derived cast";
break;
case CFITCK_UnrelatedCast:
CheckKindStr = "cast to unrelated type";
break;
case CFITCK_ICall:
Die();
}
Diag(Loc, DL_Error, "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;
else
Diag(Vtable, DL_Note, "invalid vtable");
} else {
Diag(Vtable, DL_Note, "vtable is of type %0")
<< TypeName(DTI.getMostDerivedTypeName());
}
}
} // namespace __ubsan
#endif // CAN_SANITIZE_UB

View File

@@ -0,0 +1,39 @@
//===-- ubsan_handlers_cxx.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Entry points to the runtime library for Clang's undefined behavior sanitizer,
// for C++-specific checks. This code is not linked into C binaries.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_HANDLERS_CXX_H
#define UBSAN_HANDLERS_CXX_H
#include "ubsan_value.h"
namespace __ubsan {
struct DynamicTypeCacheMissData {
SourceLocation Loc;
const TypeDescriptor &Type;
void *TypeInfo;
unsigned char TypeCheckKind;
};
/// \brief Handle a runtime type check failure, caused by an incorrect vptr.
/// When this handler is called, all we know is that the type was not in the
/// cache; this does not necessarily imply the existence of a bug.
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __ubsan_handle_dynamic_type_cache_miss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
}
#endif // UBSAN_HANDLERS_H

View File

@@ -0,0 +1,65 @@
//===-- ubsan_init.cc -----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Initialization of UBSan runtime.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
#include "ubsan_diag.h"
#include "ubsan_init.h"
#include "ubsan_flags.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
using namespace __ubsan;
const char *__ubsan::GetSanititizerToolName() {
return "UndefinedBehaviorSanitizer";
}
static bool ubsan_initialized;
static StaticSpinMutex ubsan_init_mu;
static void CommonInit() {
InitializeSuppressions();
}
static void CommonStandaloneInit() {
SanitizerToolName = GetSanititizerToolName();
CacheBinaryName();
InitializeFlags();
__sanitizer_set_report_path(common_flags()->log_path);
AndroidLogInit();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
CommonInit();
}
void __ubsan::InitAsStandalone() {
SpinMutexLock l(&ubsan_init_mu);
if (!ubsan_initialized) {
CommonStandaloneInit();
ubsan_initialized = true;
}
}
void __ubsan::InitAsStandaloneIfNecessary() { return InitAsStandalone(); }
void __ubsan::InitAsPlugin() {
SpinMutexLock l(&ubsan_init_mu);
if (!ubsan_initialized) {
CommonInit();
ubsan_initialized = true;
}
}
#endif // CAN_SANITIZE_UB

View File

@@ -0,0 +1,34 @@
//===-- ubsan_init.h --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Initialization function for UBSan runtime.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_INIT_H
#define UBSAN_INIT_H
namespace __ubsan {
// Get the full tool name for UBSan.
const char *GetSanititizerToolName();
// Initialize UBSan as a standalone tool. Typically should be called early
// during initialization.
void InitAsStandalone();
// Initialize UBSan as a standalone tool, if it hasn't been initialized before.
void InitAsStandaloneIfNecessary();
// Initializes UBSan as a plugin tool. This function should be called once
// from "parent tool" (e.g. ASan) initialization.
void InitAsPlugin();
} // namespace __ubsan
#endif // UBSAN_INIT_H

View File

@@ -0,0 +1,34 @@
//===-- ubsan_init_standalone.cc ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Initialization of standalone UBSan runtime.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if !CAN_SANITIZE_UB
# error "UBSan is not supported on this platform!"
#endif
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "ubsan_init.h"
#include "ubsan_signals_standalone.h"
namespace __ubsan {
class UbsanStandaloneInitializer {
public:
UbsanStandaloneInitializer() {
InitAsStandalone();
InitializeDeadlySignals();
}
};
static UbsanStandaloneInitializer ubsan_standalone_initializer;
} // namespace __ubsan

View File

@@ -0,0 +1,54 @@
//===-- ubsan_interface.inc -----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Ubsan interface list.
//===----------------------------------------------------------------------===//
INTERFACE_FUNCTION(__ubsan_handle_add_overflow)
INTERFACE_FUNCTION(__ubsan_handle_add_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_builtin_unreachable)
INTERFACE_FUNCTION(__ubsan_handle_cfi_bad_type)
INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail)
INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail_abort)
INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow)
INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss)
INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss_abort)
INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow)
INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch)
INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_abort)
INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin)
INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort)
INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value)
INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value_abort)
INTERFACE_FUNCTION(__ubsan_handle_missing_return)
INTERFACE_FUNCTION(__ubsan_handle_mul_overflow)
INTERFACE_FUNCTION(__ubsan_handle_mul_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_negate_overflow)
INTERFACE_FUNCTION(__ubsan_handle_negate_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg)
INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg_abort)
INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1)
INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1_abort)
INTERFACE_FUNCTION(__ubsan_handle_nullability_arg)
INTERFACE_FUNCTION(__ubsan_handle_nullability_arg_abort)
INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1)
INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1_abort)
INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds)
INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort)
INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow)
INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds)
INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds_abort)
INTERFACE_FUNCTION(__ubsan_handle_sub_overflow)
INTERFACE_FUNCTION(__ubsan_handle_sub_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1)
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)

View File

@@ -0,0 +1,29 @@
//===-- ubsan_platform.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines the platforms which UBSan is supported at.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_PLATFORM_H
#define UBSAN_PLATFORM_H
// Other platforms should be easy to add, and probably work as-is.
#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
defined(__NetBSD__)) && \
(defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \
defined(__s390__)) || (defined(__sun__) && defined(__svr4__))
# define CAN_SANITIZE_UB 1
#elif defined(_WIN32) || defined(__Fuchsia__)
# define CAN_SANITIZE_UB 1
#else
# define CAN_SANITIZE_UB 0
#endif
#endif

View File

@@ -0,0 +1,53 @@
//=-- ubsan_signals_standalone.cc
//------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Installs signal handlers and related interceptors for UBSan standalone.
//
//===----------------------------------------------------------------------===//
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "ubsan_diag.h"
#include "ubsan_init.h"
#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
#include "sanitizer_common/sanitizer_signal_interceptors.inc"
namespace __ubsan {
#if SANITIZER_FUCHSIA
void InitializeDeadlySignals() {}
#else
static void OnStackUnwind(const SignalContext &sig, const void *,
BufferedStackTrace *stack) {
GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context,
common_flags()->fast_unwind_on_fatal);
}
static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) {
HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr);
}
static bool is_initialized = false;
void InitializeDeadlySignals() {
if (is_initialized)
return;
is_initialized = true;
InitializeSignalInterceptors();
InstallDeadlySignalHandlers(&UBsanOnDeadlySignal);
}
#endif
} // namespace __ubsan
#endif // CAN_SANITIZE_UB

View File

@@ -0,0 +1,25 @@
//=-- ubsan_signals_standalone.h
//------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Installs signal handlers and related interceptors for UBSan standalone.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_SIGNALS_STANDALONE_H
#define UBSAN_SIGNALS_STANDALONE_H
namespace __ubsan {
// Initializes signal handlers and interceptors.
void InitializeDeadlySignals();
} // namespace __ubsan
#endif // UBSAN_SIGNALS_STANDALONE_H

Some files were not shown because too many files have changed in this diff Show More