summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--lib/asan/asan_activation.cc9
-rw-r--r--lib/asan/asan_flags.cc25
-rw-r--r--lib/asan/asan_flags.h3
-rw-r--r--lib/asan/tests/CMakeLists.txt3
-rw-r--r--lib/dfsan/CMakeLists.txt2
-rw-r--r--lib/dfsan/dfsan.cc11
-rw-r--r--lib/dfsan/dfsan.h1
-rw-r--r--lib/lsan/lsan_common.cc18
-rw-r--r--lib/lsan/lsan_common.h1
-rw-r--r--lib/msan/msan.cc50
-rw-r--r--lib/msan/msan_flags.h1
-rw-r--r--lib/sanitizer_common/CMakeLists.txt2
-rw-r--r--lib/sanitizer_common/sanitizer_allocator_internal.h9
-rw-r--r--lib/sanitizer_common/sanitizer_flag_parser.cc117
-rw-r--r--lib/sanitizer_common/sanitizer_flag_parser.h117
-rw-r--r--lib/sanitizer_common/sanitizer_flags.cc146
-rw-r--r--lib/sanitizer_common/sanitizer_flags.h19
-rw-r--r--lib/sanitizer_common/sanitizer_libc.cc8
-rw-r--r--lib/sanitizer_common/sanitizer_libc.h1
-rw-r--r--lib/sanitizer_common/tests/sanitizer_flags_test.cc80
-rw-r--r--lib/tsan/dd/dd_rtl.cc7
-rw-r--r--lib/tsan/rtl/tsan_flags.cc21
-rw-r--r--lib/ubsan/ubsan_flags.cc47
-rw-r--r--lib/ubsan/ubsan_flags.h4
-rw-r--r--lib/ubsan/ubsan_init.cc5
-rw-r--r--test/asan/TestCases/asan_options-help.cc9
-rw-r--r--test/asan/TestCases/asan_options-invalid.cc7
-rw-r--r--test/asan/TestCases/default_options.cc4
-rw-r--r--test/lsan/TestCases/ignore_object.cc3
-rw-r--r--test/lsan/TestCases/ignore_object_errors.cc4
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr.cpp16
32 files changed, 471 insertions, 281 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f8f52630b..f79e7dbe7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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.
diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc
index a90484aa8..1ee99cd24 100644
--- a/lib/asan/asan_activation.cc
+++ b/lib/asan/asan_activation.cc
@@ -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;
diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc
index 2c2d5c8f1..d73e43370 100644
--- a/lib/asan/asan_flags.cc
+++ b/lib/asan/asan_flags.cc
@@ -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:
diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h
index 32937e837..7653543f6 100644
--- a/lib/asan/asan_flags.h
+++ b/lib/asan/asan_flags.h
@@ -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
diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt
index b1e34c7f8..cdebf9aa0 100644
--- a/lib/asan/tests/CMakeLists.txt
+++ b/lib/asan/tests/CMakeLists.txt
@@ -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.
diff --git a/lib/dfsan/CMakeLists.txt b/lib/dfsan/CMakeLists.txt
index 257a15a93..971146aa3 100644
--- a/lib/dfsan/CMakeLists.txt
+++ b/lib/dfsan/CMakeLists.txt
@@ -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)
diff --git a/lib/dfsan/dfsan.cc b/lib/dfsan/dfsan.cc
index b8eb1f22d..dd0ea6114 100644
--- a/lib/dfsan/dfsan.cc
+++ b/lib/dfsan/dfsan.cc
@@ -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() {
diff --git a/lib/dfsan/dfsan.h b/lib/dfsan/dfsan.h
index 8f242197f..ceba3533a 100644
--- a/lib/dfsan/dfsan.h
+++ b/lib/dfsan/dfsan.h
@@ -61,7 +61,6 @@ struct Flags {
#undef DFSAN_FLAG
void SetDefaults();
- void ParseFromString(const char *str);
};
extern Flags flags_data;
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 7c52526a5..80cf1322a 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -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(...) \
diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h
index b82b9a727..64cbef38c 100644
--- a/lib/lsan/lsan_common.h
+++ b/lib/lsan/lsan_common.h
@@ -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);
}
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index 6eccb5bf6..c8bd6039c 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -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_;
+
+ 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;
+ }
+};
-#define MSAN_FLAG(Type, Name, DefaultValue, Description) \
- ParseFlag(str, &Name, #Name, Description);
+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());
+
+ parser.ParseString(options);
- f->ParseFromString(options);
- ParseCommonFlagsFromString(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();
diff --git a/lib/msan/msan_flags.h b/lib/msan/msan_flags.h
index 5ec684dfc..4fc6d172a 100644
--- a/lib/msan/msan_flags.h
+++ b/lib/msan/msan_flags.h
@@ -21,7 +21,6 @@ struct Flags {
#undef MSAN_FLAG
void SetDefaults();
- void ParseFromString(const char *str);
};
Flags *flags();
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index f4ee72a22..86697e7f7 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -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
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index 4409fd65b..9b9cfd0b5 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.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
diff --git a/lib/sanitizer_common/sanitizer_flag_parser.cc b/lib/sanitizer_common/sanitizer_flag_parser.cc
new file mode 100644
index 000000000..96ee728e8
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_flag_parser.cc
@@ -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
diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h
new file mode 100644
index 000000000..fe55f7a6f
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_flag_parser.h
@@ -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
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index b4ab1d940..b0ae4afb3 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -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
diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h
index 9f0352a57..90f3bbfbf 100644
--- a/lib/sanitizer_common/sanitizer_flags.h
+++ b/lib/sanitizer_common/sanitizer_flags.h
@@ -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
diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc
index d8bd1cf7a..862cf68e7 100644
--- a/lib/sanitizer_common/sanitizer_libc.cc
+++ b/lib/sanitizer_common/sanitizer_libc.cc
@@ -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;
diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h
index 9321e8736..0f264f106 100644
--- a/lib/sanitizer_common/sanitizer_libc.h
+++ b/lib/sanitizer_common/sanitizer_libc.h
@@ -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);
diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
index a8962917e..65adee07d 100644
--- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc
@@ -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);
diff --git a/lib/tsan/dd/dd_rtl.cc b/lib/tsan/dd/dd_rtl.cc
index 8728740f4..fe7077c20 100644
--- a/lib/tsan/dd/dd_rtl.cc
+++ b/lib/tsan/dd/dd_rtl.cc
@@ -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() {
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 77677ebba..b99d92fc8 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -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"
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
index d25481e73..7bd23a8b1 100644
--- a/lib/ubsan/ubsan_flags.cc
+++ b/lib/ubsan/ubsan_flags.cc
@@ -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
diff --git a/lib/ubsan/ubsan_flags.h b/lib/ubsan/ubsan_flags.h
index 44c287e3d..b47f14e1e 100644
--- a/lib/ubsan/ubsan_flags.h
+++ b/lib/ubsan/ubsan_flags.h
@@ -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
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
index dbafbac81..48fa49248 100644
--- a/lib/ubsan/ubsan_init.cc
+++ b/lib/ubsan/ubsan_init.cc
@@ -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;
diff --git a/test/asan/TestCases/asan_options-help.cc b/test/asan/TestCases/asan_options-help.cc
new file mode 100644
index 000000000..f10830f16
--- /dev/null
+++ b/test/asan/TestCases/asan_options-help.cc
@@ -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
diff --git a/test/asan/TestCases/asan_options-invalid.cc b/test/asan/TestCases/asan_options-invalid.cc
new file mode 100644
index 000000000..ced2481ca
--- /dev/null
+++ b/test/asan/TestCases/asan_options-invalid.cc
@@ -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
diff --git a/test/asan/TestCases/default_options.cc b/test/asan/TestCases/default_options.cc
index 6453f66a9..9a6eaeb0b 100644
--- a/test/asan/TestCases/default_options.cc
+++ b/test/asan/TestCases/default_options.cc
@@ -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;
}
diff --git a/test/lsan/TestCases/ignore_object.cc b/test/lsan/TestCases/ignore_object.cc
index 38d76e679..ac69e12a4 100644
--- a/test/lsan/TestCases/ignore_object.cc
+++ b/test/lsan/TestCases/ignore_object.cc
@@ -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)
diff --git a/test/lsan/TestCases/ignore_object_errors.cc b/test/lsan/TestCases/ignore_object_errors.cc
index 39b9b0288..41603274a 100644
--- a/test/lsan/TestCases/ignore_object_errors.cc
+++ b/test/lsan/TestCases/ignore_object_errors.cc
@@ -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
diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp
index 2d0b9a5e7..98eac271c 100644
--- a/test/ubsan/TestCases/TypeCheck/vptr.cpp
+++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp
@@ -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