forked from OSchip/llvm-project
[sanitizer] Flag parser rewrite.
The new parser is a lot stricter about syntax, reports unrecognized flags, and will make it easier to implemented some of the planned features. llvm-svn: 226169
This commit is contained in:
parent
1a1a7d0f30
commit
f294d5b829
|
@ -234,7 +234,7 @@ append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COM
|
|||
append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections SANITIZER_COMMON_CFLAGS)
|
||||
append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
|
||||
# append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
|
||||
|
||||
if(MSVC)
|
||||
# Replace the /MD[d] flags with /MT.
|
||||
|
|
|
@ -32,6 +32,9 @@ static struct AsanDeactivatedFlags {
|
|||
void OverrideFromActivationFlags() {
|
||||
Flags f;
|
||||
CommonFlags cf;
|
||||
FlagParser parser;
|
||||
RegisterAsanFlags(&parser, &f);
|
||||
RegisterCommonFlags(&parser, &cf);
|
||||
|
||||
// Copy the current activation flags.
|
||||
allocator_options.CopyTo(&f, &cf);
|
||||
|
@ -44,15 +47,13 @@ static struct AsanDeactivatedFlags {
|
|||
// FIXME: Add diagnostic to check that activation flags string doesn't
|
||||
// contain any other flags.
|
||||
if (const char *env = GetEnv("ASAN_ACTIVATION_OPTIONS")) {
|
||||
cf.ParseFromString(env);
|
||||
f.ParseFromString(env);
|
||||
parser.ParseString(env);
|
||||
}
|
||||
|
||||
// Override from getprop asan.options.
|
||||
char buf[100];
|
||||
GetExtraActivationFlags(buf, sizeof(buf));
|
||||
cf.ParseFromString(buf);
|
||||
f.ParseFromString(buf);
|
||||
parser.ParseString(buf);
|
||||
|
||||
allocator_options.SetFrom(&f, &cf);
|
||||
malloc_context_size = cf.malloc_context_size;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "lsan/lsan_common.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
|
@ -45,14 +46,18 @@ void Flags::SetDefaults() {
|
|||
#undef ASAN_FLAG
|
||||
}
|
||||
|
||||
void Flags::ParseFromString(const char *str) {
|
||||
#define ASAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
void RegisterAsanFlags(FlagParser *parser, Flags *f) {
|
||||
#define ASAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &f->Name);
|
||||
#include "asan_flags.inc"
|
||||
#undef ASAN_FLAG
|
||||
}
|
||||
|
||||
void InitializeFlags(Flags *f) {
|
||||
FlagParser parser;
|
||||
RegisterAsanFlags(&parser, f);
|
||||
RegisterCommonFlags(&parser);
|
||||
|
||||
SetCommonFlagsDefaults();
|
||||
{
|
||||
CommonFlags cf;
|
||||
|
@ -69,20 +74,17 @@ void InitializeFlags(Flags *f) {
|
|||
|
||||
// Override from compile definition.
|
||||
const char *compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
|
||||
ParseCommonFlagsFromString(compile_def);
|
||||
f->ParseFromString(compile_def);
|
||||
parser.ParseString(compile_def);
|
||||
|
||||
// Override from user-specified string.
|
||||
const char *default_options = MaybeCallAsanDefaultOptions();
|
||||
ParseCommonFlagsFromString(default_options);
|
||||
f->ParseFromString(default_options);
|
||||
parser.ParseString(default_options);
|
||||
VReport(1, "Using the defaults from __asan_default_options: %s\n",
|
||||
MaybeCallAsanDefaultOptions());
|
||||
|
||||
// Override from command line.
|
||||
if (const char *env = GetEnv("ASAN_OPTIONS")) {
|
||||
ParseCommonFlagsFromString(env);
|
||||
f->ParseFromString(env);
|
||||
parser.ParseString(env);
|
||||
VReport(1, "Parsed ASAN_OPTIONS: %s\n", env);
|
||||
}
|
||||
|
||||
|
@ -91,14 +93,13 @@ void InitializeFlags(Flags *f) {
|
|||
if (!flags()->start_deactivated) {
|
||||
char buf[100];
|
||||
GetExtraActivationFlags(buf, sizeof(buf));
|
||||
ParseCommonFlagsFromString(buf);
|
||||
f->ParseFromString(buf);
|
||||
parser.ParseString(buf);
|
||||
if (buf[0] != '\0')
|
||||
VReport(1, "Parsed activation flags: %s\n", buf);
|
||||
}
|
||||
|
||||
if (common_flags()->help) {
|
||||
PrintFlagDescriptions();
|
||||
parser.PrintFlagDescriptions();
|
||||
}
|
||||
|
||||
// Flag validation:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define ASAN_FLAGS_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
|
||||
// ASan flag values can be defined in four ways:
|
||||
// 1) initialized with default values at startup.
|
||||
|
@ -34,13 +35,13 @@ struct Flags {
|
|||
#undef ASAN_FLAG
|
||||
|
||||
void SetDefaults();
|
||||
void ParseFromString(const char *str);
|
||||
};
|
||||
|
||||
extern Flags asan_flags_dont_use_directly;
|
||||
inline Flags *flags() {
|
||||
return &asan_flags_dont_use_directly;
|
||||
}
|
||||
void RegisterAsanFlags(FlagParser *parser, Flags *f);
|
||||
void InitializeFlags(Flags *f);
|
||||
|
||||
} // namespace __asan
|
||||
|
|
|
@ -30,7 +30,8 @@ set(ASAN_UNITTEST_COMMON_CFLAGS
|
|||
-fno-rtti
|
||||
-O2
|
||||
-Wno-format
|
||||
-Werror=sign-compare)
|
||||
-Werror=sign-compare
|
||||
-Wno-non-virtual-dtor)
|
||||
append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros ASAN_UNITTEST_COMMON_CFLAGS)
|
||||
|
||||
# -gline-tables-only must be enough for ASan, so use it if possible.
|
||||
|
|
|
@ -5,7 +5,7 @@ set(DFSAN_RTL_SOURCES
|
|||
dfsan.cc
|
||||
dfsan_custom.cc
|
||||
dfsan_interceptors.cc)
|
||||
set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
|
||||
set(DFSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS} -fno-rtti)
|
||||
# Prevent clang from generating libc calls.
|
||||
append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DFSAN_COMMON_CFLAGS)
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
#include "dfsan/dfsan.h"
|
||||
|
@ -316,16 +317,18 @@ void Flags::SetDefaults() {
|
|||
#undef DFSAN_FLAG
|
||||
}
|
||||
|
||||
void Flags::ParseFromString(const char *str) {
|
||||
#define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
void RegisterDfsanFlags(FlagParser *parser, Flags *f) {
|
||||
#define DFSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &f->Name);
|
||||
#include "dfsan_flags.inc"
|
||||
#undef DFSAN_FLAG
|
||||
}
|
||||
|
||||
static void InitializeFlags(Flags &f, const char *env) {
|
||||
FlagParser parser;
|
||||
RegisterDfsanFlags(&parser, &f);
|
||||
f.SetDefaults();
|
||||
f.ParseFromString(env);
|
||||
parser.ParseString(env);
|
||||
}
|
||||
|
||||
static void dfsan_fini() {
|
||||
|
|
|
@ -61,7 +61,6 @@ struct Flags {
|
|||
#undef DFSAN_FLAG
|
||||
|
||||
void SetDefaults();
|
||||
void ParseFromString(const char *str);
|
||||
};
|
||||
|
||||
extern Flags flags_data;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_placement_new.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
|
@ -42,19 +43,20 @@ void Flags::SetDefaults() {
|
|||
#undef LSAN_FLAG
|
||||
}
|
||||
|
||||
void Flags::ParseFromString(const char *str) {
|
||||
#define LSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
static void RegisterLsanFlags(FlagParser *parser, Flags *f) {
|
||||
#define LSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &f->Name);
|
||||
#include "lsan_flags.inc"
|
||||
#undef LSAN_FLAG
|
||||
}
|
||||
|
||||
static void InitializeFlags(bool standalone) {
|
||||
Flags *f = flags();
|
||||
f->SetDefaults();
|
||||
FlagParser parser;
|
||||
RegisterLsanFlags(&parser, f);
|
||||
RegisterCommonFlags(&parser);
|
||||
|
||||
const char *options = GetEnv("LSAN_OPTIONS");
|
||||
f->ParseFromString(options);
|
||||
f->SetDefaults();
|
||||
|
||||
// Set defaults for common flags (only in standalone mode) and parse
|
||||
// them from LSAN_OPTIONS.
|
||||
|
@ -67,7 +69,9 @@ static void InitializeFlags(bool standalone) {
|
|||
cf.detect_leaks = true;
|
||||
OverrideCommonFlags(cf);
|
||||
}
|
||||
ParseCommonFlagsFromString(options);
|
||||
|
||||
const char *options = GetEnv("LSAN_OPTIONS");
|
||||
parser.ParseString(options);
|
||||
}
|
||||
|
||||
#define LOG_POINTERS(...) \
|
||||
|
|
|
@ -43,7 +43,6 @@ struct Flags {
|
|||
#undef LSAN_FLAG
|
||||
|
||||
void SetDefaults();
|
||||
void ParseFromString(const char *str);
|
||||
uptr pointer_alignment() const {
|
||||
return use_unaligned ? 1 : sizeof(uptr);
|
||||
}
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
|
||||
|
||||
// ACHTUNG! No system header includes in this file.
|
||||
|
||||
using namespace __sanitizer;
|
||||
|
@ -102,20 +102,40 @@ void Flags::SetDefaults() {
|
|||
#undef MSAN_FLAG
|
||||
}
|
||||
|
||||
void Flags::ParseFromString(const char *str) {
|
||||
// keep_going is an old name for halt_on_error,
|
||||
// and it has inverse meaning.
|
||||
halt_on_error = !halt_on_error;
|
||||
ParseFlag(str, &halt_on_error, "keep_going", "");
|
||||
halt_on_error = !halt_on_error;
|
||||
// keep_going is an old name for halt_on_error,
|
||||
// and it has inverse meaning.
|
||||
class FlagHandlerKeepGoing : public FlagHandlerBase {
|
||||
bool *halt_on_error_;
|
||||
|
||||
#define MSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
public:
|
||||
explicit FlagHandlerKeepGoing(bool *halt_on_error)
|
||||
: halt_on_error_(halt_on_error) {}
|
||||
bool Parse(const char *value) {
|
||||
bool tmp;
|
||||
FlagHandler<bool> h(&tmp);
|
||||
if (!h.Parse(value)) return false;
|
||||
*halt_on_error_ = !tmp;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void RegisterMsanFlags(FlagParser *parser, Flags *f) {
|
||||
#define MSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &f->Name);
|
||||
#include "msan_flags.inc"
|
||||
#undef MSAN_FLAG
|
||||
|
||||
FlagHandlerKeepGoing *fh_keep_going =
|
||||
new (INTERNAL_ALLOC) FlagHandlerKeepGoing(&f->halt_on_error); // NOLINT
|
||||
parser->RegisterHandler("keep_going", fh_keep_going,
|
||||
"deprecated, use halt_on_error");
|
||||
}
|
||||
|
||||
static void InitializeFlags(Flags *f, const char *options) {
|
||||
FlagParser parser;
|
||||
RegisterMsanFlags(&parser, f);
|
||||
RegisterCommonFlags(&parser);
|
||||
|
||||
SetCommonFlagsDefaults();
|
||||
{
|
||||
CommonFlags cf;
|
||||
|
@ -132,13 +152,12 @@ static void InitializeFlags(Flags *f, const char *options) {
|
|||
f->SetDefaults();
|
||||
|
||||
// Override from user-specified string.
|
||||
if (__msan_default_options) {
|
||||
f->ParseFromString(__msan_default_options());
|
||||
ParseCommonFlagsFromString(__msan_default_options());
|
||||
}
|
||||
if (__msan_default_options)
|
||||
parser.ParseString(__msan_default_options());
|
||||
|
||||
f->ParseFromString(options);
|
||||
ParseCommonFlagsFromString(options);
|
||||
parser.ParseString(options);
|
||||
|
||||
if (common_flags()->help) parser.PrintFlagDescriptions();
|
||||
|
||||
// Check flag values:
|
||||
if (f->exit_code < 0 || f->exit_code > 127) {
|
||||
|
@ -328,7 +347,6 @@ void __msan_init() {
|
|||
|
||||
const char *msan_options = GetEnv("MSAN_OPTIONS");
|
||||
InitializeFlags(&msan_flags, msan_options);
|
||||
if (common_flags()->help) PrintFlagDescriptions();
|
||||
__sanitizer_set_report_path(common_flags()->log_path);
|
||||
|
||||
InitializeInterceptors();
|
||||
|
|
|
@ -21,7 +21,6 @@ struct Flags {
|
|||
#undef MSAN_FLAG
|
||||
|
||||
void SetDefaults();
|
||||
void ParseFromString(const char *str);
|
||||
};
|
||||
|
||||
Flags *flags();
|
||||
|
|
|
@ -7,6 +7,7 @@ set(SANITIZER_SOURCES
|
|||
sanitizer_deadlock_detector1.cc
|
||||
sanitizer_deadlock_detector2.cc
|
||||
sanitizer_flags.cc
|
||||
sanitizer_flag_parser.cc
|
||||
sanitizer_libc.cc
|
||||
sanitizer_libignore.cc
|
||||
sanitizer_linux.cc
|
||||
|
@ -63,6 +64,7 @@ set(SANITIZER_HEADERS
|
|||
sanitizer_common_syscalls.inc
|
||||
sanitizer_deadlock_detector.h
|
||||
sanitizer_deadlock_detector_interface.h
|
||||
sanitizer_flag_parser.h
|
||||
sanitizer_flags.h
|
||||
sanitizer_flags.inc
|
||||
sanitizer_internal_defs.h
|
||||
|
|
|
@ -49,6 +49,15 @@ void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0);
|
|||
void InternalFree(void *p, InternalAllocatorCache *cache = 0);
|
||||
InternalAllocator *internal_allocator();
|
||||
|
||||
enum InternalAllocEnum {
|
||||
INTERNAL_ALLOC
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
inline void *operator new(__sanitizer::operator_new_size_type size,
|
||||
InternalAllocEnum) {
|
||||
return InternalAlloc(size);
|
||||
}
|
||||
|
||||
#endif // SANITIZER_ALLOCATOR_INTERNAL_H
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
//===-- sanitizer_flag_parser.cc ------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_flag_parser.h"
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_flags.h"
|
||||
#include "sanitizer_flag_parser.h"
|
||||
#include "sanitizer_allocator_internal.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
void FlagParser::PrintFlagDescriptions() {
|
||||
Printf("Available flags for %s:\n", SanitizerToolName);
|
||||
for (int i = 0; i < n_flags_; ++i)
|
||||
Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc);
|
||||
}
|
||||
|
||||
void FlagParser::fatal_error(const char *err) {
|
||||
Printf("ERROR: %s\n", err);
|
||||
Die();
|
||||
}
|
||||
|
||||
bool FlagParser::is_space(char c) {
|
||||
return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' ||
|
||||
c == '\r';
|
||||
}
|
||||
|
||||
void FlagParser::skip_whitespace() {
|
||||
while (is_space(buf_[pos_])) ++pos_;
|
||||
}
|
||||
|
||||
void FlagParser::parse_flag() {
|
||||
uptr name_start = pos_;
|
||||
while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_;
|
||||
if (buf_[pos_] != '=') fatal_error("expected '='");
|
||||
const char *name = internal_strndup(buf_ + name_start, pos_ - name_start);
|
||||
|
||||
uptr value_start = ++pos_;
|
||||
const char *value;
|
||||
if (buf_[pos_] == '\'' || buf_[pos_] == '"') {
|
||||
char quote = buf_[pos_++];
|
||||
while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_;
|
||||
if (buf_[pos_] == 0) fatal_error("unterminated string");
|
||||
value = internal_strndup(buf_ + value_start + 1, pos_ - value_start - 1);
|
||||
++pos_; // consume the closing quote
|
||||
} else {
|
||||
while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_;
|
||||
if (buf_[pos_] != 0 && !is_space(buf_[pos_]))
|
||||
fatal_error("expected separator or eol");
|
||||
value = internal_strndup(buf_ + value_start, pos_ - value_start);
|
||||
}
|
||||
|
||||
bool res = run_handler(name, value);
|
||||
if (!res) {
|
||||
Printf("Flag parsing failed.");
|
||||
Die();
|
||||
}
|
||||
InternalFree((void *)name);
|
||||
InternalFree((void *)value);
|
||||
}
|
||||
|
||||
void FlagParser::ParseString(const char *s) {
|
||||
if (!s) return;
|
||||
buf_ = s;
|
||||
pos_ = 0;
|
||||
while (true) {
|
||||
skip_whitespace();
|
||||
if (buf_[pos_] == 0) break;
|
||||
parse_flag();
|
||||
}
|
||||
|
||||
// Do a sanity check for certain flags.
|
||||
if (common_flags_dont_use.malloc_context_size < 1)
|
||||
common_flags_dont_use.malloc_context_size = 1;
|
||||
}
|
||||
|
||||
bool FlagParser::run_handler(const char *name, const char *value) {
|
||||
for (int i = 0; i < n_flags_; ++i) {
|
||||
if (internal_strcmp(name, flags_[i].name) == 0)
|
||||
return flags_[i].handler->Parse(value);
|
||||
}
|
||||
Printf("ERROR: Unknown flag: '%s'\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler,
|
||||
const char *desc) {
|
||||
CHECK(n_flags_ < kMaxFlags);
|
||||
flags_[n_flags_].name = name;
|
||||
flags_[n_flags_].desc = desc;
|
||||
flags_[n_flags_].handler = handler;
|
||||
++n_flags_;
|
||||
}
|
||||
|
||||
FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
|
||||
flags_ = (Flag *)InternalAlloc(sizeof(Flag) * kMaxFlags);
|
||||
}
|
||||
|
||||
FlagParser::~FlagParser() {
|
||||
for (int i = 0; i < n_flags_; ++i)
|
||||
InternalFree(flags_[i].handler);
|
||||
InternalFree(flags_);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
|
@ -0,0 +1,117 @@
|
|||
//===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_FLAG_REGISTRY_H
|
||||
#define SANITIZER_FLAG_REGISTRY_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_allocator_internal.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
class FlagHandlerBase {
|
||||
public:
|
||||
virtual bool Parse(const char *value) { return false; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class FlagHandler : public FlagHandlerBase {
|
||||
T *t_;
|
||||
|
||||
public:
|
||||
explicit FlagHandler(T *t) : t_(t) {}
|
||||
bool Parse(const char *value);
|
||||
};
|
||||
|
||||
template <>
|
||||
inline bool FlagHandler<bool>::Parse(const char *value) {
|
||||
if (internal_strcmp(value, "0") == 0 ||
|
||||
internal_strcmp(value, "no") == 0 ||
|
||||
internal_strcmp(value, "false") == 0) {
|
||||
*t_ = false;
|
||||
return true;
|
||||
}
|
||||
if (internal_strcmp(value, "1") == 0 ||
|
||||
internal_strcmp(value, "yes") == 0 ||
|
||||
internal_strcmp(value, "true") == 0) {
|
||||
*t_ = true;
|
||||
return true;
|
||||
}
|
||||
Printf("ERROR: Invalid value for bool option: '%s'\n", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool FlagHandler<const char *>::Parse(const char *value) {
|
||||
*t_ = internal_strdup(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool FlagHandler<int>::Parse(const char *value) {
|
||||
char *value_end;
|
||||
*t_ = internal_simple_strtoll(value, &value_end, 10);
|
||||
bool ok = *value_end == 0;
|
||||
if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
|
||||
return ok;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool FlagHandler<uptr>::Parse(const char *value) {
|
||||
char *value_end;
|
||||
*t_ = internal_simple_strtoll(value, &value_end, 10);
|
||||
bool ok = *value_end == 0;
|
||||
if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
|
||||
return ok;
|
||||
}
|
||||
|
||||
class FlagParser {
|
||||
static const int kMaxFlags = 200;
|
||||
struct Flag {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
FlagHandlerBase *handler;
|
||||
} *flags_;
|
||||
int n_flags_;
|
||||
|
||||
const char *buf_;
|
||||
uptr pos_;
|
||||
|
||||
public:
|
||||
FlagParser();
|
||||
~FlagParser();
|
||||
void RegisterHandler(const char *name, FlagHandlerBase *handler,
|
||||
const char *desc);
|
||||
void ParseString(const char *s);
|
||||
void PrintFlagDescriptions();
|
||||
|
||||
private:
|
||||
void fatal_error(const char *err);
|
||||
bool is_space(char c);
|
||||
void skip_whitespace();
|
||||
void parse_flag();
|
||||
bool run_handler(const char *name, const char *value);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
|
||||
T *var) {
|
||||
FlagHandler<T> *fh = new (INTERNAL_ALLOC) FlagHandler<T>(var); // NOLINT
|
||||
parser->RegisterHandler(name, fh, desc);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_FLAG_REGISTRY_H
|
|
@ -16,6 +16,7 @@
|
|||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_list.h"
|
||||
#include "sanitizer_flag_parser.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
|
@ -40,150 +41,15 @@ void CommonFlags::SetDefaults() {
|
|||
#undef COMMON_FLAG
|
||||
}
|
||||
|
||||
void CommonFlags::ParseFromString(const char *str) {
|
||||
#define COMMON_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
#include "sanitizer_flags.inc"
|
||||
#undef COMMON_FLAG
|
||||
// Do a sanity check for certain flags.
|
||||
if (malloc_context_size < 1)
|
||||
malloc_context_size = 1;
|
||||
}
|
||||
|
||||
void CommonFlags::CopyFrom(const CommonFlags &other) {
|
||||
internal_memcpy(this, &other, sizeof(*this));
|
||||
}
|
||||
|
||||
static bool GetFlagValue(const char *env, const char *name,
|
||||
const char **value, int *value_length) {
|
||||
if (env == 0)
|
||||
return false;
|
||||
const char *pos = 0;
|
||||
for (;;) {
|
||||
pos = internal_strstr(env, name);
|
||||
if (pos == 0)
|
||||
return false;
|
||||
const char *name_end = pos + internal_strlen(name);
|
||||
if ((pos != env &&
|
||||
((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) ||
|
||||
*name_end != '=') {
|
||||
// Seems to be middle of another flag name or value.
|
||||
env = pos + 1;
|
||||
continue;
|
||||
}
|
||||
pos = name_end;
|
||||
break;
|
||||
}
|
||||
const char *end;
|
||||
if (pos[0] != '=') {
|
||||
end = pos;
|
||||
} else {
|
||||
pos += 1;
|
||||
if (pos[0] == '"') {
|
||||
pos += 1;
|
||||
end = internal_strchr(pos, '"');
|
||||
} else if (pos[0] == '\'') {
|
||||
pos += 1;
|
||||
end = internal_strchr(pos, '\'');
|
||||
} else {
|
||||
// Read until the next space or colon.
|
||||
end = pos + internal_strcspn(pos, " :\r\n\t");
|
||||
}
|
||||
if (end == 0)
|
||||
end = pos + internal_strlen(pos);
|
||||
}
|
||||
*value = pos;
|
||||
*value_length = end - pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool StartsWith(const char *flag, int flag_length, const char *value) {
|
||||
if (!flag || !value)
|
||||
return false;
|
||||
int value_length = internal_strlen(value);
|
||||
return (flag_length >= value_length) &&
|
||||
(0 == internal_strncmp(flag, value, value_length));
|
||||
}
|
||||
|
||||
static LowLevelAllocator allocator_for_flags;
|
||||
|
||||
// The linear scan is suboptimal, but the number of flags is relatively small.
|
||||
bool FlagInDescriptionList(const char *name) {
|
||||
IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
|
||||
while (it.hasNext()) {
|
||||
if (!internal_strcmp(it.next()->name, name)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddFlagDescription(const char *name, const char *description) {
|
||||
if (FlagInDescriptionList(name)) return;
|
||||
FlagDescription *new_description = new(allocator_for_flags) FlagDescription;
|
||||
new_description->name = name;
|
||||
new_description->description = description;
|
||||
flag_descriptions.push_back(new_description);
|
||||
}
|
||||
|
||||
// TODO(glider): put the descriptions inside CommonFlags.
|
||||
void PrintFlagDescriptions() {
|
||||
IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
|
||||
Printf("Available flags for %s:\n", SanitizerToolName);
|
||||
while (it.hasNext()) {
|
||||
FlagDescription *descr = it.next();
|
||||
Printf("\t%s\n\t\t- %s\n", descr->name, descr->description);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseFlag(const char *env, bool *flag,
|
||||
const char *name, const char *descr) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
AddFlagDescription(name, descr);
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
if (StartsWith(value, value_length, "0") ||
|
||||
StartsWith(value, value_length, "no") ||
|
||||
StartsWith(value, value_length, "false"))
|
||||
*flag = false;
|
||||
if (StartsWith(value, value_length, "1") ||
|
||||
StartsWith(value, value_length, "yes") ||
|
||||
StartsWith(value, value_length, "true"))
|
||||
*flag = true;
|
||||
}
|
||||
|
||||
void ParseFlag(const char *env, int *flag,
|
||||
const char *name, const char *descr) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
AddFlagDescription(name, descr);
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
*flag = static_cast<int>(internal_atoll(value));
|
||||
}
|
||||
|
||||
void ParseFlag(const char *env, uptr *flag,
|
||||
const char *name, const char *descr) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
AddFlagDescription(name, descr);
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
*flag = static_cast<uptr>(internal_atoll(value));
|
||||
}
|
||||
|
||||
void ParseFlag(const char *env, const char **flag,
|
||||
const char *name, const char *descr) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
AddFlagDescription(name, descr);
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
// Copy the flag value. Don't use locks here, as flags are parsed at
|
||||
// tool startup.
|
||||
char *value_copy = (char*)(allocator_for_flags.Allocate(value_length + 1));
|
||||
internal_memcpy(value_copy, value, value_length);
|
||||
value_copy[value_length] = '\0';
|
||||
*flag = value_copy;
|
||||
void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
|
||||
#define COMMON_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &cf->Name);
|
||||
#include "sanitizer_flags.inc"
|
||||
#undef COMMON_FLAG
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -18,22 +18,12 @@
|
|||
|
||||
namespace __sanitizer {
|
||||
|
||||
void ParseFlag(const char *env, bool *flag,
|
||||
const char *name, const char *descr);
|
||||
void ParseFlag(const char *env, int *flag,
|
||||
const char *name, const char *descr);
|
||||
void ParseFlag(const char *env, uptr *flag,
|
||||
const char *name, const char *descr);
|
||||
void ParseFlag(const char *env, const char **flag,
|
||||
const char *name, const char *descr);
|
||||
|
||||
struct CommonFlags {
|
||||
#define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name;
|
||||
#include "sanitizer_flags.inc"
|
||||
#undef COMMON_FLAG
|
||||
|
||||
void SetDefaults();
|
||||
void ParseFromString(const char *str);
|
||||
void CopyFrom(const CommonFlags &other);
|
||||
};
|
||||
|
||||
|
@ -47,10 +37,6 @@ inline void SetCommonFlagsDefaults() {
|
|||
common_flags_dont_use.SetDefaults();
|
||||
}
|
||||
|
||||
inline void ParseCommonFlagsFromString(const char *str) {
|
||||
common_flags_dont_use.ParseFromString(str);
|
||||
}
|
||||
|
||||
// This function can only be used to setup tool-specific overrides for
|
||||
// CommonFlags defaults. Generally, it should only be used right after
|
||||
// SetCommonFlagsDefaults(), but before ParseCommonFlagsFromString(), and
|
||||
|
@ -60,8 +46,9 @@ inline void OverrideCommonFlags(const CommonFlags &cf) {
|
|||
common_flags_dont_use.CopyFrom(cf);
|
||||
}
|
||||
|
||||
void PrintFlagDescriptions();
|
||||
|
||||
class FlagParser;
|
||||
void RegisterCommonFlags(FlagParser *parser,
|
||||
CommonFlags *cf = &common_flags_dont_use);
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_FLAGS_H
|
||||
|
|
|
@ -101,6 +101,14 @@ char* internal_strdup(const char *s) {
|
|||
return s2;
|
||||
}
|
||||
|
||||
char* internal_strndup(const char *s, uptr n) {
|
||||
uptr len = internal_strnlen(s, n);
|
||||
char *s2 = (char*)InternalAlloc(len + 1);
|
||||
internal_memcpy(s2, s, len);
|
||||
s2[len] = 0;
|
||||
return s2;
|
||||
}
|
||||
|
||||
int internal_strcmp(const char *s1, const char *s2) {
|
||||
while (true) {
|
||||
unsigned c1 = *s1;
|
||||
|
|
|
@ -38,6 +38,7 @@ char *internal_strchrnul(const char *s, int c);
|
|||
int internal_strcmp(const char *s1, const char *s2);
|
||||
uptr internal_strcspn(const char *s, const char *reject);
|
||||
char *internal_strdup(const char *s);
|
||||
char *internal_strndup(const char *s, uptr n);
|
||||
uptr internal_strlen(const char *s);
|
||||
char *internal_strncat(char *dst, const char *src, uptr n);
|
||||
int internal_strncmp(const char *s1, const char *s2, uptr n);
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_allocator_internal.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <string.h>
|
||||
|
@ -20,58 +22,74 @@
|
|||
namespace __sanitizer {
|
||||
|
||||
static const char kFlagName[] = "flag_name";
|
||||
static const char kFlagDesc[] = "flag description";
|
||||
|
||||
template <typename T>
|
||||
static void TestFlag(T start_value, const char *env, T final_value) {
|
||||
T flag = start_value;
|
||||
ParseFlag(env, &flag, kFlagName, "flag description");
|
||||
|
||||
FlagParser parser;
|
||||
RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
|
||||
|
||||
parser.ParseString(env);
|
||||
|
||||
EXPECT_EQ(final_value, flag);
|
||||
}
|
||||
|
||||
static void TestStrFlag(const char *start_value, const char *env,
|
||||
const char *final_value) {
|
||||
template <>
|
||||
void TestFlag(const char *start_value, const char *env,
|
||||
const char *final_value) {
|
||||
const char *flag = start_value;
|
||||
ParseFlag(env, &flag, kFlagName, "flag description");
|
||||
|
||||
FlagParser parser;
|
||||
RegisterFlag(&parser, kFlagName, kFlagDesc, &flag);
|
||||
|
||||
parser.ParseString(env);
|
||||
|
||||
EXPECT_EQ(0, internal_strcmp(final_value, flag));
|
||||
}
|
||||
|
||||
TEST(SanitizerCommon, BooleanFlags) {
|
||||
TestFlag(true, "--flag_name", true);
|
||||
TestFlag(false, "flag_name", false);
|
||||
TestFlag(false, "--flag_name=1", true);
|
||||
TestFlag(true, "asdas flag_name=0 asdas", false);
|
||||
TestFlag(true, " --flag_name=0 ", false);
|
||||
TestFlag(false, "flag_name=1", true);
|
||||
TestFlag(false, "flag_name=yes", true);
|
||||
TestFlag(false, "flag_name=true", true);
|
||||
TestFlag(true, "flag_name=0", false);
|
||||
TestFlag(true, "flag_name=no", false);
|
||||
TestFlag(true, "flag_name=false", false);
|
||||
}
|
||||
|
||||
TEST(SanitizerCommon, IntFlags) {
|
||||
TestFlag(-11, 0, -11);
|
||||
TestFlag(-11, "flag_name", -11);
|
||||
TestFlag(-11, "--flag_name=", 0);
|
||||
TestFlag(-11, "--flag_name=42", 42);
|
||||
TestFlag(-11, "--flag_name=-42", -42);
|
||||
TestFlag(-11, "flag_name=0", 0);
|
||||
TestFlag(-11, "flag_name=42", 42);
|
||||
TestFlag(-11, "flag_name=-42", -42);
|
||||
EXPECT_DEATH(TestFlag(-11, "flag_name", 0), "expected '='");
|
||||
EXPECT_DEATH(TestFlag(-11, "--flag_name=42", 0),
|
||||
"Unknown flag: '--flag_name'");
|
||||
}
|
||||
|
||||
TEST(SanitizerCommon, StrFlags) {
|
||||
TestStrFlag("zzz", 0, "zzz");
|
||||
TestStrFlag("zzz", "flag_name", "zzz");
|
||||
TestStrFlag("zzz", "--flag_name=", "");
|
||||
TestStrFlag("", "--flag_name=abc", "abc");
|
||||
TestStrFlag("", "--flag_name='abc zxc'", "abc zxc");
|
||||
TestStrFlag("", "--flag_name='abc zxcc'", "abc zxcc");
|
||||
TestStrFlag("", "--flag_name=\"abc qwe\" asd", "abc qwe");
|
||||
TestStrFlag("", "other_flag_name=zzz", "");
|
||||
TestFlag("zzz", 0, "zzz");
|
||||
TestFlag("zzz", "flag_name=", "");
|
||||
TestFlag("zzz", "flag_name=abc", "abc");
|
||||
TestFlag("", "flag_name=abc", "abc");
|
||||
TestFlag("", "flag_name='abc zxc'", "abc zxc");
|
||||
// TestStrFlag("", "flag_name=\"abc qwe\" asd", "abc qwe");
|
||||
}
|
||||
|
||||
static void TestTwoFlags(const char *env, bool expected_flag1,
|
||||
const char *expected_flag2) {
|
||||
const char *expected_flag2,
|
||||
const char *name1 = "flag1",
|
||||
const char *name2 = "flag2") {
|
||||
bool flag1 = !expected_flag1;
|
||||
const char *flag2 = "";
|
||||
ParseFlag(env, &flag1, "flag1", "flag1 description");
|
||||
ParseFlag(env, &flag2, "flag2", "flag2 description");
|
||||
|
||||
FlagParser parser;
|
||||
RegisterFlag(&parser, name1, kFlagDesc, &flag1);
|
||||
RegisterFlag(&parser, name2, kFlagDesc, &flag2);
|
||||
|
||||
parser.ParseString(env);
|
||||
|
||||
EXPECT_EQ(expected_flag1, flag1);
|
||||
EXPECT_EQ(0, internal_strcmp(flag2, expected_flag2));
|
||||
}
|
||||
|
@ -86,8 +104,20 @@ TEST(SanitizerCommon, MultipleFlags) {
|
|||
TestTwoFlags("flag2=qxx\tflag1=yes", true, "qxx");
|
||||
}
|
||||
|
||||
TEST(SanitizerCommon, CommonSuffixFlags) {
|
||||
TestTwoFlags("flag=1 other_flag='zzz'", true, "zzz", "flag", "other_flag");
|
||||
TestTwoFlags("other_flag='zzz' flag=1", true, "zzz", "flag", "other_flag");
|
||||
TestTwoFlags("other_flag=' flag=0 ' flag=1", true, " flag=0 ", "flag",
|
||||
"other_flag");
|
||||
TestTwoFlags("flag=1 other_flag=' flag=0 '", true, " flag=0 ", "flag",
|
||||
"other_flag");
|
||||
}
|
||||
|
||||
TEST(SanitizerCommon, CommonFlags) {
|
||||
CommonFlags cf;
|
||||
FlagParser parser;
|
||||
RegisterCommonFlags(&parser, &cf);
|
||||
|
||||
cf.SetDefaults();
|
||||
EXPECT_TRUE(cf.symbolize);
|
||||
EXPECT_STREQ(".", cf.coverage_dir);
|
||||
|
@ -97,7 +127,7 @@ TEST(SanitizerCommon, CommonFlags) {
|
|||
cf.coverage_direct = true;
|
||||
cf.log_path = "path/one";
|
||||
|
||||
cf.ParseFromString("symbolize=1:coverage_direct=false log_path='path/two'");
|
||||
parser.ParseString("symbolize=1:coverage_direct=false log_path='path/two'");
|
||||
EXPECT_TRUE(cf.symbolize);
|
||||
EXPECT_TRUE(cf.coverage);
|
||||
EXPECT_FALSE(cf.coverage_direct);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_placement_new.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
|
||||
|
@ -80,8 +81,10 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
}
|
||||
|
||||
// Override from command line.
|
||||
ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
|
||||
ParseCommonFlagsFromString(env);
|
||||
FlagParser parser;
|
||||
RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
|
||||
RegisterCommonFlags(&parser);
|
||||
parser.ParseString(env);
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "tsan_flags.h"
|
||||
#include "tsan_rtl.h"
|
||||
|
@ -41,16 +42,18 @@ void Flags::SetDefaults() {
|
|||
second_deadlock_stack = false;
|
||||
}
|
||||
|
||||
void Flags::ParseFromString(const char *str) {
|
||||
#define TSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
void RegisterTsanFlags(FlagParser *parser, Flags *f) {
|
||||
#define TSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &f->Name);
|
||||
#include "tsan_flags.inc"
|
||||
#undef TSAN_FLAG
|
||||
// DDFlags
|
||||
ParseFlag(str, &second_deadlock_stack, "second_deadlock_stack", "");
|
||||
}
|
||||
|
||||
void InitializeFlags(Flags *f, const char *env) {
|
||||
FlagParser parser;
|
||||
RegisterTsanFlags(&parser, f);
|
||||
RegisterCommonFlags(&parser);
|
||||
|
||||
f->SetDefaults();
|
||||
|
||||
SetCommonFlagsDefaults();
|
||||
|
@ -66,11 +69,9 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
}
|
||||
|
||||
// Let a frontend override.
|
||||
f->ParseFromString(__tsan_default_options());
|
||||
ParseCommonFlagsFromString(__tsan_default_options());
|
||||
parser.ParseString(__tsan_default_options());
|
||||
// Override from command line.
|
||||
f->ParseFromString(env);
|
||||
ParseCommonFlagsFromString(env);
|
||||
parser.ParseString(env);
|
||||
|
||||
// Sanity check.
|
||||
if (!f->report_bugs) {
|
||||
|
@ -80,7 +81,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
}
|
||||
|
||||
if (common_flags()->help)
|
||||
PrintFlagDescriptions();
|
||||
parser.PrintFlagDescriptions();
|
||||
|
||||
if (f->history_size < 0 || f->history_size > 7) {
|
||||
Printf("ThreadSanitizer: incorrect value for history_size"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "ubsan_flags.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
|
||||
namespace __ubsan {
|
||||
|
||||
|
@ -21,18 +22,6 @@ static const char *MaybeCallUbsanDefaultOptions() {
|
|||
return (&__ubsan_default_options) ? __ubsan_default_options() : "";
|
||||
}
|
||||
|
||||
void InitializeCommonFlags() {
|
||||
SetCommonFlagsDefaults();
|
||||
CommonFlags cf;
|
||||
cf.CopyFrom(*common_flags());
|
||||
cf.print_summary = false;
|
||||
OverrideCommonFlags(cf);
|
||||
// Override from user-specified string.
|
||||
ParseCommonFlagsFromString(MaybeCallUbsanDefaultOptions());
|
||||
// Override from environment variable.
|
||||
ParseCommonFlagsFromString(GetEnv("UBSAN_OPTIONS"));
|
||||
}
|
||||
|
||||
Flags ubsan_flags;
|
||||
|
||||
void Flags::SetDefaults() {
|
||||
|
@ -41,20 +30,42 @@ void Flags::SetDefaults() {
|
|||
#undef UBSAN_FLAG
|
||||
}
|
||||
|
||||
void Flags::ParseFromString(const char *str) {
|
||||
#define UBSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
ParseFlag(str, &Name, #Name, Description);
|
||||
void RegisterUbsanFlags(FlagParser *parser, Flags *f) {
|
||||
#define UBSAN_FLAG(Type, Name, DefaultValue, Description) \
|
||||
RegisterFlag(parser, #Name, Description, &f->Name);
|
||||
#include "ubsan_flags.inc"
|
||||
#undef UBSAN_FLAG
|
||||
}
|
||||
|
||||
void InitializeFlags() {
|
||||
void InitializeFlags(bool standalone) {
|
||||
Flags *f = flags();
|
||||
FlagParser parser;
|
||||
RegisterUbsanFlags(&parser, f);
|
||||
|
||||
if (standalone) {
|
||||
RegisterCommonFlags(&parser);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
f->SetDefaults();
|
||||
// Override from user-specified string.
|
||||
f->ParseFromString(MaybeCallUbsanDefaultOptions());
|
||||
parser.ParseString(MaybeCallUbsanDefaultOptions());
|
||||
// Override from environment variable.
|
||||
f->ParseFromString(GetEnv("UBSAN_OPTIONS"));
|
||||
parser.ParseString(GetEnv("UBSAN_OPTIONS"));
|
||||
}
|
||||
|
||||
} // namespace __ubsan
|
||||
|
|
|
@ -23,14 +23,12 @@ struct Flags {
|
|||
#undef UBSAN_FLAG
|
||||
|
||||
void SetDefaults();
|
||||
void ParseFromString(const char *str);
|
||||
};
|
||||
|
||||
extern Flags ubsan_flags;
|
||||
inline Flags *flags() { return &ubsan_flags; }
|
||||
|
||||
void InitializeCommonFlags();
|
||||
void InitializeFlags();
|
||||
void InitializeFlags(bool standalone);
|
||||
|
||||
} // namespace __ubsan
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ void __ubsan::InitIfNecessary() {
|
|||
#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
|
||||
|
@ -38,10 +39,10 @@ void __ubsan::InitIfNecessary() {
|
|||
// common flags. It means, that we are not allowed to *use* common flags
|
||||
// in this function.
|
||||
SanitizerToolName = "UndefinedBehaviorSanitizer";
|
||||
InitializeCommonFlags();
|
||||
standalone = true;
|
||||
}
|
||||
// Initialize UBSan-specific flags.
|
||||
InitializeFlags();
|
||||
InitializeFlags(standalone);
|
||||
SuppressionContext::InitIfNecessary();
|
||||
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
|
||||
ubsan_inited = true;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: ASAN_OPTIONS=help=1 %run %t 2>&1 | FileCheck %s
|
||||
|
||||
int main() {
|
||||
}
|
||||
|
||||
// CHECK: Available flags for AddressSanitizer:
|
||||
// CHECK-DAG: handle_segv
|
||||
// CHECK-DAG: check_initialization_order
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: %clangxx_asan -O0 %s -o %t
|
||||
// RUN: ASAN_OPTIONS=invalid_option_name=10 not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
int main() {
|
||||
}
|
||||
|
||||
// CHECK: Unknown flag{{.*}}invalid_option_name
|
|
@ -4,12 +4,12 @@
|
|||
// __asan_default_options() are not supported on Windows.
|
||||
// XFAIL: win32
|
||||
|
||||
const char *kAsanDefaultOptions="verbosity=1 foo=bar";
|
||||
const char *kAsanDefaultOptions="verbosity=1 strip_path_prefix=bar";
|
||||
|
||||
extern "C"
|
||||
__attribute__((no_sanitize_address))
|
||||
const char *__asan_default_options() {
|
||||
// CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar
|
||||
// CHECK: Using the defaults from __asan_default_options: {{.*}} strip_path_prefix=bar
|
||||
return kAsanDefaultOptions;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Test for __lsan_ignore_object().
|
||||
// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=2"
|
||||
// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0"
|
||||
// RUN: %clangxx_lsan %s -o %t
|
||||
// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
|
@ -20,5 +20,4 @@ int main() {
|
|||
return 0;
|
||||
}
|
||||
// CHECK: Test alloc: [[ADDR:.*]].
|
||||
// CHECK: ignoring heap object at [[ADDR]]
|
||||
// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// Test for incorrect use of __lsan_ignore_object().
|
||||
// RUN: LSAN_BASE="verbosity=2"
|
||||
// RUN: %clangxx_lsan %s -o %t
|
||||
// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s
|
||||
|
||||
|
@ -18,5 +17,4 @@ int main() {
|
|||
return 0;
|
||||
}
|
||||
// CHECK: Test alloc: [[ADDR:.*]].
|
||||
// CHECK: heap object at [[ADDR]] is already being ignored
|
||||
// CHECK: no heap object found at [[ADDR]]
|
||||
// CHECK-NOT: SUMMARY: {{.*}} leaked
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
// RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
|
||||
|
||||
// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mS 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fS 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cS 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mV 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fV 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cV 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t oU 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mS 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fS 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cS 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mV 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fV 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cV 2>&1
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t oU 2>&1
|
||||
|
||||
// RUN: echo "vptr_check:S" > %t.loc-supp
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.loc-supp':halt_on_error=1" UBSAN_OPTIONS="suppressions='%t.loc-supp':halt_on_error=1" not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
|
||||
// RUN: ASAN_OPTIONS="suppressions='%t.loc-supp'" UBSAN_OPTIONS="suppressions='%t.loc-supp':halt_on_error=1" not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
|
||||
|
||||
// FIXME: This test produces linker errors on Darwin.
|
||||
// XFAIL: darwin
|
||||
|
|
Loading…
Reference in New Issue