From 6eb53d6460183b51a2cde13b30031572af65d3fe Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Fri, 25 Jul 2014 22:24:34 +0000 Subject: [PATCH] [UBSan] Call UBSan initialization as early as possible. Specifically, use .preinit_array initialization on Linux and dynamic global initializer on another platforms. Historically UBSan didn't have any initialization code and its runtime was stateless. This is no longer the case - UBSan relies on some non-trivial functionality from sanitizer_common (e.g. online symbolization) and is now configurable by runtime flags. Additionally, we've dropped support for enabling UBSan only for a few shared objects, so UBSan is now always linked into the main executable, so now we can use similar initialization as all the rest sanitizers. llvm-svn: 213983 --- compiler-rt/lib/ubsan/CMakeLists.txt | 1 + compiler-rt/lib/ubsan/ubsan_diag.cc | 30 +++-------------- compiler-rt/lib/ubsan/ubsan_init.cc | 63 ++++++++++++++++++++++++++++++++++++ compiler-rt/lib/ubsan/ubsan_init.h | 24 ++++++++++++++ 4 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 compiler-rt/lib/ubsan/ubsan_init.cc create mode 100644 compiler-rt/lib/ubsan/ubsan_init.h diff --git a/compiler-rt/lib/ubsan/CMakeLists.txt b/compiler-rt/lib/ubsan/CMakeLists.txt index 14e3dce..7174392 100644 --- a/compiler-rt/lib/ubsan/CMakeLists.txt +++ b/compiler-rt/lib/ubsan/CMakeLists.txt @@ -2,6 +2,7 @@ set(UBSAN_SOURCES ubsan_diag.cc + ubsan_init.cc ubsan_flags.cc ubsan_handlers.cc ubsan_value.cc diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc index c19f2f5..87beb62 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cc +++ b/compiler-rt/lib/ubsan/ubsan_diag.cc @@ -12,10 +12,8 @@ //===----------------------------------------------------------------------===// #include "ubsan_diag.h" +#include "ubsan_init.h" #include "ubsan_flags.h" -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_flags.h" -#include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_symbolizer.h" @@ -23,28 +21,8 @@ using namespace __ubsan; -static void InitializeSanitizerCommonAndFlags() { - static StaticSpinMutex init_mu; - SpinMutexLock l(&init_mu); - static bool initialized; - if (initialized) - return; - if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) { - // UBSan is run in a standalone mode. Initialize it now. - SanitizerToolName = "UndefinedBehaviorSanitizer"; - CommonFlags *cf = common_flags(); - SetCommonFlagsDefaults(cf); - cf->print_summary = false; - // Common flags may only be modified via UBSAN_OPTIONS. - ParseCommonFlagsFromString(cf, GetEnv("UBSAN_OPTIONS")); - } - // Initialize UBSan-specific flags. - InitializeFlags(); - initialized = true; -} - void __ubsan::MaybePrintStackTrace(uptr pc, uptr bp) { - // We assume that flags are already parsed: InitializeSanitizerCommonAndFlags + // We assume that flags are already parsed: InitIfNecessary // will definitely be called when we print the first diagnostics message. if (!flags()->print_stacktrace) return; @@ -82,7 +60,7 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) { Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) { if (!Loc) return Location(); - InitializeSanitizerCommonAndFlags(); + InitIfNecessary(); AddressInfo Info; if (!Symbolizer::GetOrInit()->SymbolizePC(Loc, &Info, 1) || @@ -296,7 +274,7 @@ static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc, } Diag::~Diag() { - InitializeSanitizerCommonAndFlags(); + InitIfNecessary(); Decorator Decor; SpinMutexLock l(&CommonSanitizerReportMutex); Printf(Decor.Bold()); diff --git a/compiler-rt/lib/ubsan/ubsan_init.cc b/compiler-rt/lib/ubsan/ubsan_init.cc new file mode 100644 index 0000000..9cfd42f --- /dev/null +++ b/compiler-rt/lib/ubsan/ubsan_init.cc @@ -0,0 +1,63 @@ +//===-- 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_init.h" +#include "ubsan_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_mutex.h" + +using namespace __ubsan; + +static bool ubsan_inited; + +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; + 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"; + CommonFlags *cf = common_flags(); + SetCommonFlagsDefaults(cf); + cf->print_summary = false; + // Common flags may only be modified via UBSAN_OPTIONS. + ParseCommonFlagsFromString(cf, GetEnv("UBSAN_OPTIONS")); + } + // Initialize UBSan-specific flags. + InitializeFlags(); + ubsan_inited = true; +} + +#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(); + } +}; +static UbsanInitializer ubsan_initializer; +#endif // SANITIZER_CAN_USE_PREINIT_ARRAY diff --git a/compiler-rt/lib/ubsan/ubsan_init.h b/compiler-rt/lib/ubsan/ubsan_init.h new file mode 100644 index 0000000..18356cf --- /dev/null +++ b/compiler-rt/lib/ubsan/ubsan_init.h @@ -0,0 +1,24 @@ +//===-- 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 { + +// 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(); + +} // namespace __ubsan + +#endif // UBSAN_INIT_H -- 2.7.4