summaryrefslogtreecommitdiff
path: root/lib/ubsan
diff options
context:
space:
mode:
authorAlexey Samsonov <vonosmas@gmail.com>2015-04-01 22:42:36 +0000
committerAlexey Samsonov <vonosmas@gmail.com>2015-04-01 22:42:36 +0000
commitb05184a2968adf141d964bee0852a849e79f4181 (patch)
tree9ca6614d778e61c158cc1b9323204f8cc3c7f30a /lib/ubsan
parent06dcedbe140962d536e109a010e25f184a63fa05 (diff)
downloadcompiler-rt-b05184a2968adf141d964bee0852a849e79f4181.tar.gz
[UBSan] Embed UBSan into ASan runtime (compiler-rt part).
Summary: Change the way we use ASan and UBSan together. Instead of keeping two separate runtimes (libclang_rt.asan and libclang_rt.ubsan), embed UBSan into ASan and get rid of libclang_rt.ubsan. If UBSan is not supported on a platform, all UBSan sources are just compiled into dummy empty object files. UBSan initialization code (e.g. flag parsing) is directly called from ASan initialization, so we are able to enforce correct initialization order. This mirrors the approach we already use for ASan+LSan. This change doesn't modify the way we use standalone UBSan. Test Plan: regression test suite Reviewers: kubabrecka, zaks.anna, rsmith, kcc Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D8646 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@233861 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ubsan')
-rw-r--r--lib/ubsan/CMakeLists.txt53
-rw-r--r--lib/ubsan/Makefile.mk4
-rw-r--r--lib/ubsan/ubsan_diag.cc11
-rw-r--r--lib/ubsan/ubsan_flags.cc29
-rw-r--r--lib/ubsan/ubsan_flags.h9
-rw-r--r--lib/ubsan/ubsan_init.cc77
-rw-r--r--lib/ubsan/ubsan_init.h13
-rw-r--r--lib/ubsan/ubsan_init_standalone.cc34
-rw-r--r--lib/ubsan/ubsan_platform.h1
9 files changed, 143 insertions, 88 deletions
diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt
index a8b3f61ef..4ea0f5067 100644
--- a/lib/ubsan/CMakeLists.txt
+++ b/lib/ubsan/CMakeLists.txt
@@ -8,6 +8,10 @@ set(UBSAN_SOURCES
ubsan_value.cc
)
+set(UBSAN_STANDALONE_SOURCES
+ ubsan_init_standalone.cc
+ )
+
set(UBSAN_CXX_SOURCES
ubsan_handlers_cxx.cc
ubsan_type_hash.cc
@@ -17,64 +21,69 @@ include_directories(..)
set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS})
append_no_rtti_flag(UBSAN_CFLAGS)
+set(UBSAN_STANDALONE_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_no_rtti_flag(UBSAN_STANDALONE_CFLAGS)
set(UBSAN_CXXFLAGS ${SANITIZER_COMMON_CFLAGS})
add_custom_target(ubsan)
if(APPLE)
foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS})
+ # Common parts of UBSan runtime.
add_compiler_rt_darwin_object_library(RTUbsan ${os}
- ARCH ${UBSAN_SUPPORTED_ARCH}
+ ARCH ${UBSAN_COMMON_SUPPORTED_ARCH}
SOURCES ${UBSAN_SOURCES} ${UBSAN_CXX_SOURCES}
CFLAGS ${UBSAN_CXXFLAGS})
- add_compiler_rt_darwin_dynamic_runtime(clang_rt.ubsan_${os}_dynamic ${os}
- ARCH ${UBSAN_SUPPORTED_ARCH}
- SOURCES $<TARGET_OBJECTS:RTUbsan.${os}>
- $<TARGET_OBJECTS:RTSanitizerCommon.${os}>
- LINKFLAGS -lc++abi)
+ if(UBSAN_SUPPORTED_ARCH)
+ # Initializer of standalone UBSan runtime.
+ add_compiler_rt_darwin_object_library(RTUbsan_standalone ${os}
+ ARCH ${UBSAN_SUPPORTED_ARCH}
+ SOURCES ${UBSAN_STANDALONE_SOURCES}
+ CFLAGS ${UBSAN_STANDALONE_CFLAGS})
+
+ add_compiler_rt_darwin_dynamic_runtime(clang_rt.ubsan_${os}_dynamic ${os}
+ ARCH ${UBSAN_SUPPORTED_ARCH}
+ SOURCES $<TARGET_OBJECTS:RTUbsan.${os}>
+ $<TARGET_OBJECTS:RTUbsan_standalone.${os}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${os}>)
- add_dependencies(ubsan clang_rt.ubsan_${os}_dynamic)
+ add_dependencies(ubsan clang_rt.ubsan_${os}_dynamic)
+ endif()
endforeach()
else()
- # Build separate libraries for each target.
- foreach(arch ${UBSAN_SUPPORTED_ARCH})
+ # Common parts of UBSan runtime.
+ foreach(arch ${UBSAN_COMMON_SUPPORTED_ARCH})
add_compiler_rt_object_library(RTUbsan ${arch}
SOURCES ${UBSAN_SOURCES} CFLAGS ${UBSAN_CFLAGS})
# C++-specific parts of UBSan runtime. Requires a C++ ABI library.
add_compiler_rt_object_library(RTUbsan_cxx ${arch}
SOURCES ${UBSAN_CXX_SOURCES} CFLAGS ${UBSAN_CXXFLAGS})
+ endforeach()
+
+ foreach(arch ${UBSAN_SUPPORTED_ARCH})
+ # Initializer of standalone UBSan runtime.
+ add_compiler_rt_object_library(RTUbsan_standalone ${arch}
+ SOURCES ${UBSAN_STANDALONE_SOURCES} CFLAGS ${UBSAN_STANDALONE_CFLAGS})
# Standalone UBSan runtimes.
add_compiler_rt_runtime(clang_rt.ubsan_standalone-${arch} ${arch} STATIC
SOURCES $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTUbsan.${arch}>
+ $<TARGET_OBJECTS:RTUbsan_standalone.${arch}>
CFLAGS ${UBSAN_CFLAGS})
add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx-${arch} ${arch} STATIC
SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
CFLAGS ${UBSAN_CXXFLAGS})
- # UBSan runtimes used when another sanitizer is available.
- add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTUbsan.${arch}>
- CFLAGS ${UBSAN_CFLAGS})
- add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC
- SOURCES $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
- CFLAGS ${UBSAN_CXXFLAGS})
add_dependencies(ubsan
- clang_rt.ubsan-${arch}
- clang_rt.ubsan_cxx-${arch}
clang_rt.ubsan_standalone-${arch}
clang_rt.ubsan_standalone_cxx-${arch})
if (UNIX AND NOT ${arch} MATCHES "i386|i686")
- add_sanitizer_rt_symbols(clang_rt.ubsan-${arch} ubsan.syms.extra)
- add_sanitizer_rt_symbols(clang_rt.ubsan_cxx-${arch} ubsan.syms.extra)
add_sanitizer_rt_symbols(clang_rt.ubsan_standalone-${arch} ubsan.syms.extra)
add_sanitizer_rt_symbols(clang_rt.ubsan_standalone_cxx-${arch} ubsan.syms.extra)
add_dependencies(ubsan
- clang_rt.ubsan-${arch}-symbols
- clang_rt.ubsan_cxx-${arch}-symbols
clang_rt.ubsan_standalone-${arch}-symbols
clang_rt.ubsan_standalone_cxx-${arch}-symbols)
endif()
diff --git a/lib/ubsan/Makefile.mk b/lib/ubsan/Makefile.mk
index d5561f41b..ec3f5c5da 100644
--- a/lib/ubsan/Makefile.mk
+++ b/lib/ubsan/Makefile.mk
@@ -11,8 +11,9 @@ ModuleName := ubsan
SubDirs :=
Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file)))
+StandaloneSources := ubsan_init_standalone.cc
CXXSources := ubsan_type_hash.cc ubsan_handlers_cxx.cc
-CSources := $(filter-out $(CXXSources),$(Sources))
+CSources := $(filter-out $(StandaloneSources),$(filter-out $(CXXSources),$(Sources)))
ObjNames := $(Sources:%.cc=%.o)
Implementation := Generic
@@ -24,3 +25,4 @@ Dependencies += $(wildcard $(Dir)/../sanitizer_common/*.h)
# Define a convenience variable for all the ubsan functions.
UbsanFunctions := $(CSources:%.cc=%)
UbsanCXXFunctions := $(CXXSources:%.cc=%)
+UbsanStandaloneFunctions := $(StandaloneSources:%.cc=%)
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index 2314fb6ed..6f76c6af3 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -27,7 +27,7 @@
using namespace __ubsan;
static void MaybePrintStackTrace(uptr pc, uptr bp) {
- // We assume that flags are already parsed: InitIfNecessary
+ // 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;
@@ -76,7 +76,7 @@ class Decorator : public SanitizerCommonDecorator {
}
SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) {
- InitIfNecessary();
+ InitAsStandaloneIfNecessary();
return Symbolizer::GetOrInit()->SymbolizePC(PC);
}
@@ -330,7 +330,7 @@ Diag::~Diag() {
ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
: Opts(Opts), SummaryLoc(SummaryLoc) {
- InitIfNecessary();
+ InitAsStandaloneIfNecessary();
CommonSanitizerReportMutex.Lock();
}
@@ -355,10 +355,7 @@ void __ubsan::InitializeSuppressions() {
}
bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
- // If .preinit_array is not used, it is possible that the UBSan runtime is not
- // initialized.
- if (!SANITIZER_CAN_USE_PREINIT_ARRAY)
- InitIfNecessary();
+ InitAsStandaloneIfNecessary();
CHECK(suppression_ctx);
Suppression *s;
return suppression_ctx->Match(TypeName, kVptrCheck, &s);
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
index 49ada8a26..eda7557a0 100644
--- a/lib/ubsan/ubsan_flags.cc
+++ b/lib/ubsan/ubsan_flags.cc
@@ -20,7 +20,7 @@
namespace __ubsan {
-static const char *MaybeCallUbsanDefaultOptions() {
+const char *MaybeCallUbsanDefaultOptions() {
return (&__ubsan_default_options) ? __ubsan_default_options() : "";
}
@@ -39,31 +39,22 @@ void RegisterUbsanFlags(FlagParser *parser, Flags *f) {
#undef UBSAN_FLAG
}
-void InitializeFlags(bool standalone) {
- Flags *f = flags();
- FlagParser parser;
- RegisterUbsanFlags(&parser, f);
-
- if (standalone) {
- RegisterCommonFlags(&parser);
-
- SetCommonFlagsDefaults();
+void InitializeFlags() {
+ SetCommonFlagsDefaults();
+ {
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.print_summary = false;
OverrideCommonFlags(cf);
- } else {
- // Ignore common flags if not standalone.
- // This is inconsistent with LSan, which allows common flags in LSAN_FLAGS.
- // This is caused by undefined initialization order between ASan and UBsan,
- // which makes it impossible to make sure that common flags from ASAN_OPTIONS
- // have not been used (in __asan_init) before they are overwritten with flags
- // from UBSAN_OPTIONS.
- CommonFlags cf_ignored;
- RegisterCommonFlags(&parser, &cf_ignored);
}
+ Flags *f = flags();
f->SetDefaults();
+
+ FlagParser parser;
+ RegisterCommonFlags(&parser);
+ RegisterUbsanFlags(&parser, f);
+
// Override from user-specified string.
parser.ParseString(MaybeCallUbsanDefaultOptions());
// Override from environment variable.
diff --git a/lib/ubsan/ubsan_flags.h b/lib/ubsan/ubsan_flags.h
index b47f14e1e..18aed9b05 100644
--- a/lib/ubsan/ubsan_flags.h
+++ b/lib/ubsan/ubsan_flags.h
@@ -15,6 +15,10 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
+namespace __sanitizer {
+class FlagParser;
+}
+
namespace __ubsan {
struct Flags {
@@ -28,7 +32,10 @@ struct Flags {
extern Flags ubsan_flags;
inline Flags *flags() { return &ubsan_flags; }
-void InitializeFlags(bool standalone);
+void InitializeFlags();
+void RegisterUbsanFlags(FlagParser *parser, Flags *f);
+
+const char *MaybeCallUbsanDefaultOptions();
} // namespace __ubsan
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
index 952726977..c3b8b6c22 100644
--- a/lib/ubsan/ubsan_init.cc
+++ b/lib/ubsan/ubsan_init.cc
@@ -23,45 +23,54 @@
using namespace __ubsan;
-static bool ubsan_inited;
+static enum {
+ UBSAN_MODE_UNKNOWN = 0,
+ UBSAN_MODE_STANDALONE,
+ UBSAN_MODE_PLUGIN
+} ubsan_mode;
+static StaticSpinMutex ubsan_init_mu;
-void __ubsan::InitIfNecessary() {
-#if !SANITIZER_CAN_USE_PREINIT_ARRAY
- // No need to lock mutex if we're initializing from preinit array.
- static StaticSpinMutex init_mu;
- SpinMutexLock l(&init_mu);
-#endif
- if (LIKELY(ubsan_inited))
- return;
- bool standalone = false;
- if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) {
- // WARNING: If this condition holds, then either UBSan runs in a standalone
- // mode, or initializer for another sanitizer hasn't run yet. In a latter
- // case, another sanitizer will overwrite "SanitizerToolName" and reparse
- // common flags. It means, that we are not allowed to *use* common flags
- // in this function.
- SanitizerToolName = "UndefinedBehaviorSanitizer";
- standalone = true;
- }
- // Initialize UBSan-specific flags.
- InitializeFlags(standalone);
+static void CommonInit() {
InitializeSuppressions();
+}
+
+static void CommonStandaloneInit() {
+ SanitizerToolName = "UndefinedBehaviorSanitizer";
+ InitializeFlags();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
- ubsan_inited = true;
+ CommonInit();
+ ubsan_mode = UBSAN_MODE_STANDALONE;
}
-#if SANITIZER_CAN_USE_PREINIT_ARRAY
-__attribute__((section(".preinit_array"), used))
-void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary;
-#else
-// Use a dynamic initializer.
-class UbsanInitializer {
- public:
- UbsanInitializer() {
- InitIfNecessary();
+void __ubsan::InitAsStandalone() {
+ if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
+ CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ CommonStandaloneInit();
+ return;
}
-};
-static UbsanInitializer ubsan_initializer;
-#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
+ SpinMutexLock l(&ubsan_init_mu);
+ CHECK_NE(UBSAN_MODE_PLUGIN, ubsan_mode);
+ if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ CommonStandaloneInit();
+}
+
+void __ubsan::InitAsStandaloneIfNecessary() {
+ if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
+ CHECK_NE(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ return;
+ }
+ SpinMutexLock l(&ubsan_init_mu);
+ if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ CommonStandaloneInit();
+}
+
+void __ubsan::InitAsPlugin() {
+#if !SANITIZER_CAN_USE_PREINIT_ARRAY
+ SpinMutexLock l(&ubsan_init_mu);
+#endif
+ CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
+ CommonInit();
+ ubsan_mode = UBSAN_MODE_PLUGIN;
+}
#endif // CAN_SANITIZE_UB
diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h
index 18356cfca..103ae24d1 100644
--- a/lib/ubsan/ubsan_init.h
+++ b/lib/ubsan/ubsan_init.h
@@ -15,9 +15,16 @@
namespace __ubsan {
-// NOTE: This function might take a lock (if .preinit_array initialization is
-// not used). It's generally a bad idea to call it on a fast path.
-void InitIfNecessary();
+// 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
diff --git a/lib/ubsan/ubsan_init_standalone.cc b/lib/ubsan/ubsan_init_standalone.cc
new file mode 100644
index 000000000..cd2da1191
--- /dev/null
+++ b/lib/ubsan/ubsan_init_standalone.cc
@@ -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 "ubsan_init.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+__attribute__((section(".preinit_array"), used))
+void (*__local_ubsan_preinit)(void) = __ubsan::InitAsStandalone;
+#else
+// Use a dynamic initializer.
+class UbsanStandaloneInitializer {
+ public:
+ UbsanStandaloneInitializer() {
+ __ubsan::InitAsStandalone();
+ }
+};
+static UbsanStandaloneInitializer ubsan_standalone_initializer;
+#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
+
diff --git a/lib/ubsan/ubsan_platform.h b/lib/ubsan/ubsan_platform.h
index 83fb42b3b..8ba253bfe 100644
--- a/lib/ubsan/ubsan_platform.h
+++ b/lib/ubsan/ubsan_platform.h
@@ -20,7 +20,6 @@
# define CAN_SANITIZE_UB 1
#else
# define CAN_SANITIZE_UB 0
-# error "UBSan not supported for this platform!"
#endif
#endif