[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

llvm-svn: 233861
diff --git a/compiler-rt/lib/CMakeLists.txt b/compiler-rt/lib/CMakeLists.txt
index 91a7037..2b6ae54 100644
--- a/compiler-rt/lib/CMakeLists.txt
+++ b/compiler-rt/lib/CMakeLists.txt
@@ -8,6 +8,7 @@
   add_subdirectory(interception)
   add_subdirectory(sanitizer_common)
   add_subdirectory(lsan)
+  add_subdirectory(ubsan)
 endif()
 
 if(COMPILER_RT_HAS_ASAN)
@@ -33,7 +34,3 @@
   add_subdirectory(tsan/dd)
 endif()
 
-if(COMPILER_RT_HAS_UBSAN)
-  add_subdirectory(ubsan)
-endif()
-
diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt
index 8b771fb..e09c94d 100644
--- a/compiler-rt/lib/asan/CMakeLists.txt
+++ b/compiler-rt/lib/asan/CMakeLists.txt
@@ -96,6 +96,7 @@
               $<TARGET_OBJECTS:RTInterception.${os}>
               $<TARGET_OBJECTS:RTSanitizerCommon.${os}>
               $<TARGET_OBJECTS:RTLSanCommon.${os}>
+              $<TARGET_OBJECTS:RTUbsan.${os}>
       CFLAGS ${ASAN_DYNAMIC_CFLAGS}
       DEFS ${ASAN_DYNAMIC_DEFINITIONS})
     add_dependencies(asan clang_rt.asan_${os}_dynamic)
@@ -107,7 +108,8 @@
       $<TARGET_OBJECTS:RTInterception.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
-      $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
+      $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+      $<TARGET_OBJECTS:RTUbsan.${arch}>)
 
     add_compiler_rt_runtime(clang_rt.asan-${arch} ${arch} STATIC
       SOURCES $<TARGET_OBJECTS:RTAsan_preinit.${arch}>
@@ -119,6 +121,7 @@
 
     add_compiler_rt_runtime(clang_rt.asan_cxx-${arch} ${arch} STATIC
       SOURCES $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
+              $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
       CFLAGS ${ASAN_CFLAGS}
       DEFS ${ASAN_COMMON_DEFINITIONS})
     add_dependencies(asan clang_rt.asan_cxx-${arch})
@@ -137,6 +140,7 @@
     add_compiler_rt_runtime(clang_rt.asan-dynamic-${arch} ${arch} SHARED
       OUTPUT_NAME ${SHARED_ASAN_NAME}
       SOURCES $<TARGET_OBJECTS:RTAsan_dynamic.${arch}>
+              $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
               ${ASAN_COMMON_RUNTIME_OBJECTS}
       CFLAGS ${ASAN_DYNAMIC_CFLAGS}
       DEFS ${ASAN_DYNAMIC_DEFINITIONS})
diff --git a/compiler-rt/lib/asan/asan_flags.cc b/compiler-rt/lib/asan/asan_flags.cc
index efb7767..e8ea549 100644
--- a/compiler-rt/lib/asan/asan_flags.cc
+++ b/compiler-rt/lib/asan/asan_flags.cc
@@ -20,6 +20,8 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_flag_parser.h"
+#include "ubsan/ubsan_flags.h"
+#include "ubsan/ubsan_platform.h"
 
 namespace __asan {
 
@@ -72,8 +74,8 @@
   RegisterAsanFlags(&asan_parser, f);
   RegisterCommonFlags(&asan_parser);
 
-  // Set the default values and prepare for parsing LSan flags (which can also
-  // overwrite common flags).
+  // Set the default values and prepare for parsing LSan and UBSan flags
+  // (which can also overwrite common flags).
 #if CAN_SANITIZE_LEAKS
   __lsan::Flags *lf = __lsan::flags();
   lf->SetDefaults();
@@ -83,6 +85,15 @@
   RegisterCommonFlags(&lsan_parser);
 #endif
 
+#if CAN_SANITIZE_UB
+  __ubsan::Flags *uf = __ubsan::flags();
+  uf->SetDefaults();
+
+  FlagParser ubsan_parser;
+  __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
+  RegisterCommonFlags(&ubsan_parser);
+#endif
+
   // Override from ASan compile definition.
   const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
   asan_parser.ParseString(asan_compile_def);
@@ -90,12 +101,19 @@
   // Override from user-specified string.
   const char *asan_default_options = MaybeCallAsanDefaultOptions();
   asan_parser.ParseString(asan_default_options);
+#if CAN_SANITIZE_UB
+  const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
+  ubsan_parser.ParseString(ubsan_default_options);
+#endif
 
   // Override from command line.
   asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
 #if CAN_SANITIZE_LEAKS
   lsan_parser.ParseString(GetEnv("LSAN_OPTIONS"));
 #endif
+#if CAN_SANITIZE_UB
+  ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
+#endif
 
   // Let activation flags override current settings. On Android they come
   // from a system property. On other platforms this is no-op.
diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc
index f346615..fcdfe5b 100644
--- a/compiler-rt/lib/asan/asan_rtl.cc
+++ b/compiler-rt/lib/asan/asan_rtl.cc
@@ -28,6 +28,8 @@
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include "lsan/lsan_common.h"
+#include "ubsan/ubsan_init.h"
+#include "ubsan/ubsan_platform.h"
 
 int __asan_option_detect_stack_use_after_return;  // Global interface symbol.
 uptr *__asan_test_only_reported_buggy_pointer;  // Used only for testing asan.
@@ -495,6 +497,10 @@
   }
 #endif  // CAN_SANITIZE_LEAKS
 
+#if CAN_SANITIZE_UB
+  __ubsan::InitAsPlugin();
+#endif
+
   InitializeSuppressions();
 
   VReport(1, "AddressSanitizer Init done\n");
diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt
index 513d128..16baf45 100644
--- a/compiler-rt/lib/asan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/asan/tests/CMakeLists.txt
@@ -214,18 +214,18 @@
       $<TARGET_OBJECTS:RTAsan.osx>
       $<TARGET_OBJECTS:RTInterception.osx>
       $<TARGET_OBJECTS:RTSanitizerCommon.osx>
-      $<TARGET_OBJECTS:RTLSanCommon.osx>)
+      $<TARGET_OBJECTS:RTLSanCommon.osx>
+      $<TARGET_OBJECTS:RTUbsan.osx>)
   else()
     set(ASAN_TEST_RUNTIME_OBJECTS
       $<TARGET_OBJECTS:RTAsan.${arch}>
       $<TARGET_OBJECTS:RTAsan_cxx.${arch}>
       $<TARGET_OBJECTS:RTInterception.${arch}>
       $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
-      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
-    if(NOT WIN32)
-      list(APPEND ASAN_TEST_RUNTIME_OBJECTS
-           $<TARGET_OBJECTS:RTLSanCommon.${arch}>)
-    endif()
+      $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+      $<TARGET_OBJECTS:RTLSanCommon.${arch}>
+      $<TARGET_OBJECTS:RTUbsan.${arch}>
+      $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>)
   endif()
   add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS})
   set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES
diff --git a/compiler-rt/lib/ubsan/CMakeLists.txt b/compiler-rt/lib/ubsan/CMakeLists.txt
index a8b3f61..4ea0f50 100644
--- a/compiler-rt/lib/ubsan/CMakeLists.txt
+++ b/compiler-rt/lib/ubsan/CMakeLists.txt
@@ -8,6 +8,10 @@
   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 @@
 
 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_dependencies(ubsan clang_rt.ubsan_${os}_dynamic)
+      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)
+    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/compiler-rt/lib/ubsan/Makefile.mk b/compiler-rt/lib/ubsan/Makefile.mk
index d5561f4..ec3f5c5 100644
--- a/compiler-rt/lib/ubsan/Makefile.mk
+++ b/compiler-rt/lib/ubsan/Makefile.mk
@@ -11,8 +11,9 @@
 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 @@
 # Define a convenience variable for all the ubsan functions.
 UbsanFunctions := $(CSources:%.cc=%)
 UbsanCXXFunctions := $(CXXSources:%.cc=%)
+UbsanStandaloneFunctions := $(StandaloneSources:%.cc=%)
diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cc b/compiler-rt/lib/ubsan/ubsan_diag.cc
index 2314fb6..6f76c6a 100644
--- a/compiler-rt/lib/ubsan/ubsan_diag.cc
+++ b/compiler-rt/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 @@
 }
 
 SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) {
-  InitIfNecessary();
+  InitAsStandaloneIfNecessary();
   return Symbolizer::GetOrInit()->SymbolizePC(PC);
 }
 
@@ -330,7 +330,7 @@
 
 ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc)
     : Opts(Opts), SummaryLoc(SummaryLoc) {
-  InitIfNecessary();
+  InitAsStandaloneIfNecessary();
   CommonSanitizerReportMutex.Lock();
 }
 
@@ -355,10 +355,7 @@
 }
 
 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/compiler-rt/lib/ubsan/ubsan_flags.cc b/compiler-rt/lib/ubsan/ubsan_flags.cc
index 49ada8a..eda7557 100644
--- a/compiler-rt/lib/ubsan/ubsan_flags.cc
+++ b/compiler-rt/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 @@
 #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/compiler-rt/lib/ubsan/ubsan_flags.h b/compiler-rt/lib/ubsan/ubsan_flags.h
index b47f14e..18aed9b 100644
--- a/compiler-rt/lib/ubsan/ubsan_flags.h
+++ b/compiler-rt/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 @@
 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/compiler-rt/lib/ubsan/ubsan_init.cc b/compiler-rt/lib/ubsan/ubsan_init.cc
index 9527269..c3b8b6c 100644
--- a/compiler-rt/lib/ubsan/ubsan_init.cc
+++ b/compiler-rt/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();
-  InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
-  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 void CommonStandaloneInit() {
+  SanitizerToolName = "UndefinedBehaviorSanitizer";
+  InitializeFlags();
+  InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
+  CommonInit();
+  ubsan_mode = UBSAN_MODE_STANDALONE;
+}
+
+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/compiler-rt/lib/ubsan/ubsan_init.h b/compiler-rt/lib/ubsan/ubsan_init.h
index 18356cf..103ae24 100644
--- a/compiler-rt/lib/ubsan/ubsan_init.h
+++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_init_standalone.cc b/compiler-rt/lib/ubsan/ubsan_init_standalone.cc
new file mode 100644
index 0000000..cd2da11
--- /dev/null
+++ b/compiler-rt/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/compiler-rt/lib/ubsan/ubsan_platform.h b/compiler-rt/lib/ubsan/ubsan_platform.h
index 83fb42b..8ba253b 100644
--- a/compiler-rt/lib/ubsan/ubsan_platform.h
+++ b/compiler-rt/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