[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
This commit is contained in:
Alexey Samsonov 2014-07-25 22:24:34 +00:00
parent ac4b69e40b
commit 6eb53d6460
4 changed files with 92 additions and 26 deletions

View File

@ -2,6 +2,7 @@
set(UBSAN_SOURCES
ubsan_diag.cc
ubsan_init.cc
ubsan_flags.cc
ubsan_handlers.cc
ubsan_value.cc

View File

@ -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());

View File

@ -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

View File

@ -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