From b05184a2968adf141d964bee0852a849e79f4181 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Wed, 1 Apr 2015 22:42:36 +0000 Subject: [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 --- lib/ubsan/CMakeLists.txt | 53 +++++++++++++++----------- lib/ubsan/Makefile.mk | 4 +- lib/ubsan/ubsan_diag.cc | 11 ++---- lib/ubsan/ubsan_flags.cc | 29 +++++--------- lib/ubsan/ubsan_flags.h | 9 ++++- lib/ubsan/ubsan_init.cc | 77 +++++++++++++++++++++----------------- lib/ubsan/ubsan_init.h | 13 +++++-- lib/ubsan/ubsan_init_standalone.cc | 34 +++++++++++++++++ lib/ubsan/ubsan_platform.h | 1 - 9 files changed, 143 insertions(+), 88 deletions(-) create mode 100644 lib/ubsan/ubsan_init_standalone.cc (limited to 'lib/ubsan') 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 $ - $ - 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 $ + $ + $) - 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 $ $ $ + $ CFLAGS ${UBSAN_CFLAGS}) add_compiler_rt_runtime(clang_rt.ubsan_standalone_cxx-${arch} ${arch} STATIC SOURCES $ CFLAGS ${UBSAN_CXXFLAGS}) - # UBSan runtimes used when another sanitizer is available. - add_compiler_rt_runtime(clang_rt.ubsan-${arch} ${arch} STATIC - SOURCES $ - CFLAGS ${UBSAN_CFLAGS}) - add_compiler_rt_runtime(clang_rt.ubsan_cxx-${arch} ${arch} STATIC - SOURCES $ - 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 -- cgit v1.2.1