From 7bd319cc089c0a65d229b67bda9e29b37bb34fa0 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 27 Nov 2013 09:54:10 +0000 Subject: [PATCH] tsan: fix flags parsing - running_on_valgrind was not parsed in some contexts - refactor code a bit - add comprehensive tests for flags parsing llvm-svn: 195831 --- compiler-rt/lib/asan/asan_rtl.cc | 9 +- compiler-rt/lib/lsan/lsan.cc | 4 +- compiler-rt/lib/msan/msan.cc | 5 +- .../lib/sanitizer_common/sanitizer_flags.cc | 6 +- .../lib/sanitizer_common/sanitizer_flags.h | 4 +- compiler-rt/lib/tsan/rtl/tsan_flags.cc | 13 +- .../lib/tsan/tests/unit/tsan_flags_test.cc | 207 ++++++++++++++++++ 7 files changed, 228 insertions(+), 20 deletions(-) diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index 11f05954d31e..a1b9fd542acb 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -88,8 +88,9 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() { } static void ParseFlagsFromString(Flags *f, const char *str) { - ParseCommonFlagsFromString(str); - CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax); + CommonFlags *cf = common_flags(); + ParseCommonFlagsFromString(cf, str); + CHECK((uptr)cf->malloc_context_size <= kStackTraceMax); ParseFlag(str, &f->quarantine_size, "quarantine_size"); ParseFlag(str, &f->redzone, "redzone"); @@ -133,7 +134,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) { void InitializeFlags(Flags *f, const char *env) { CommonFlags *cf = common_flags(); - SetCommonFlagDefaults(); + SetCommonFlagsDefaults(cf); cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf->malloc_context_size = kDefaultMallocContextSize; @@ -179,7 +180,7 @@ void InitializeFlags(Flags *f, const char *env) { // Override from user-specified string. ParseFlagsFromString(f, MaybeCallAsanDefaultOptions()); - if (common_flags()->verbosity) { + if (cf->verbosity) { Report("Using the defaults from __asan_default_options: %s\n", MaybeCallAsanDefaultOptions()); } diff --git a/compiler-rt/lib/lsan/lsan.cc b/compiler-rt/lib/lsan/lsan.cc index 058bbdba3907..43cfcda42ca9 100644 --- a/compiler-rt/lib/lsan/lsan.cc +++ b/compiler-rt/lib/lsan/lsan.cc @@ -27,12 +27,12 @@ namespace __lsan { static void InitializeCommonFlags() { CommonFlags *cf = common_flags(); - SetCommonFlagDefaults(); + SetCommonFlagsDefaults(cf); cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); cf->malloc_context_size = 30; cf->detect_leaks = true; - ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS")); + ParseCommonFlagsFromString(cf, GetEnv("LSAN_OPTIONS")); } } // namespace __lsan diff --git a/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc index 4a484520a583..890a5d93f24d 100644 --- a/compiler-rt/lib/msan/msan.cc +++ b/compiler-rt/lib/msan/msan.cc @@ -123,7 +123,8 @@ static uptr StackOriginPC[kNumStackOriginDescrs]; static atomic_uint32_t NumStackOriginDescrs; static void ParseFlagsFromString(Flags *f, const char *str) { - ParseCommonFlagsFromString(str); + CommonFlags *cf = common_flags(); + ParseCommonFlagsFromString(cf, str); ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes"); ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes"); ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc"); @@ -146,7 +147,7 @@ static void ParseFlagsFromString(Flags *f, const char *str) { static void InitializeFlags(Flags *f, const char *options) { CommonFlags *cf = common_flags(); - SetCommonFlagDefaults(); + SetCommonFlagsDefaults(cf); cf->external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH"); cf->malloc_context_size = 20; cf->handle_ioctl = true; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc index c355040c648c..4fb713c0f3ad 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc @@ -18,8 +18,7 @@ namespace __sanitizer { -void SetCommonFlagDefaults() { - CommonFlags *f = common_flags(); +void SetCommonFlagsDefaults(CommonFlags *f) { f->symbolize = true; f->external_symbolizer_path = 0; f->strip_path_prefix = ""; @@ -35,8 +34,7 @@ void SetCommonFlagDefaults() { f->print_summary = true; } -void ParseCommonFlagsFromString(const char *str) { - CommonFlags *f = common_flags(); +void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { ParseFlag(str, &f->symbolize, "symbolize"); ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path"); ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix"); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h index 63da423becfb..ffc69fe18e4b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.h @@ -61,8 +61,8 @@ inline CommonFlags *common_flags() { return &f; } -void SetCommonFlagDefaults(); -void ParseCommonFlagsFromString(const char *str); +void SetCommonFlagsDefaults(CommonFlags *f); +void ParseCommonFlagsFromString(CommonFlags *f, const char *str); } // namespace __sanitizer diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/compiler-rt/lib/tsan/rtl/tsan_flags.cc index c6f24bf49abd..a358c3b15472 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc @@ -58,6 +58,7 @@ static void ParseFlags(Flags *f, const char *env) { ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms"); ParseFlag(env, &f->memory_limit_mb, "memory_limit_mb"); ParseFlag(env, &f->stop_on_start, "stop_on_start"); + ParseFlag(env, &f->running_on_valgrind, "running_on_valgrind"); ParseFlag(env, &f->history_size, "history_size"); ParseFlag(env, &f->io_sync, "io_sync"); } @@ -91,18 +92,18 @@ void InitializeFlags(Flags *f, const char *env) { f->history_size = kGoMode ? 1 : 2; // There are a lot of goroutines in Go. f->io_sync = 1; - CommonFlags *cf = common_flags(); - SetCommonFlagDefaults(); - *static_cast(f) = *cf; + SetCommonFlagsDefaults(f); // Let a frontend override. OverrideFlags(f); ParseFlags(f, __tsan_default_options()); - ParseCommonFlagsFromString(__tsan_default_options()); + ParseCommonFlagsFromString(f, __tsan_default_options()); // Override from command line. ParseFlags(f, env); - ParseCommonFlagsFromString(env); - *static_cast(f) = *cf; + ParseCommonFlagsFromString(f, env); + + // Copy back to common flags. + *common_flags() = *f; // Sanity check. if (!f->report_bugs) { diff --git a/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc b/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc index ffb9c55b605f..388e0148b3b5 100644 --- a/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc +++ b/compiler-rt/lib/tsan/tests/unit/tsan_flags_test.cc @@ -13,6 +13,7 @@ #include "tsan_flags.h" #include "tsan_rtl.h" #include "gtest/gtest.h" +#include namespace __tsan { @@ -35,4 +36,210 @@ TEST(Flags, DefaultValues) { EXPECT_EQ(true, f.enable_annotations); } +static const char *options1 = + " enable_annotations=0" + " suppress_equal_stacks=0" + " suppress_equal_addresses=0" + " suppress_java=0" + " report_bugs=0" + " report_thread_leaks=0" + " report_destroy_locked=0" + " report_signal_unsafe=0" + " report_atomic_races=0" + " force_seq_cst_atomics=0" + " suppressions=qwerty" + " print_suppressions=0" + " print_benign=0" + " exitcode=111" + " halt_on_error=0" + " atexit_sleep_ms=222" + " profile_memory=qqq" + " flush_memory_ms=444" + " flush_symbolizer_ms=555" + " memory_limit_mb=666" + " stop_on_start=0" + " running_on_valgrind=0" + " history_size=5" + " io_sync=1" + + " symbolize=0" + " external_symbolizer_path=asdfgh" + " strip_path_prefix=zxcvb" + " fast_unwind_on_fatal=0" + " fast_unwind_on_malloc=0" + " handle_ioctl=0" + " malloc_context_size=777" + " log_path=aaa" + " verbosity=2" + " detect_leaks=0" + " leak_check_at_exit=0" + " allocator_may_return_null=0" + " print_summary=0" + ""; + +static const char *options2 = + " enable_annotations=true" + " suppress_equal_stacks=true" + " suppress_equal_addresses=true" + " suppress_java=true" + " report_bugs=true" + " report_thread_leaks=true" + " report_destroy_locked=true" + " report_signal_unsafe=true" + " report_atomic_races=true" + " force_seq_cst_atomics=true" + " suppressions=aaaaa" + " print_suppressions=true" + " print_benign=true" + " exitcode=222" + " halt_on_error=true" + " atexit_sleep_ms=123" + " profile_memory=bbbbb" + " flush_memory_ms=234" + " flush_symbolizer_ms=345" + " memory_limit_mb=456" + " stop_on_start=true" + " running_on_valgrind=true" + " history_size=6" + " io_sync=2" + + " symbolize=true" + " external_symbolizer_path=cccccc" + " strip_path_prefix=ddddddd" + " fast_unwind_on_fatal=true" + " fast_unwind_on_malloc=true" + " handle_ioctl=true" + " malloc_context_size=567" + " log_path=eeeeeee" + " verbosity=3" + " detect_leaks=true" + " leak_check_at_exit=true" + " allocator_may_return_null=true" + " print_summary=true" + ""; + +void VerifyOptions1(Flags *f) { + EXPECT_EQ(f->enable_annotations, 0); + EXPECT_EQ(f->suppress_equal_stacks, 0); + EXPECT_EQ(f->suppress_equal_addresses, 0); + EXPECT_EQ(f->suppress_java, 0); + EXPECT_EQ(f->report_bugs, 0); + EXPECT_EQ(f->report_thread_leaks, 0); + EXPECT_EQ(f->report_destroy_locked, 0); + EXPECT_EQ(f->report_signal_unsafe, 0); + EXPECT_EQ(f->report_atomic_races, 0); + EXPECT_EQ(f->force_seq_cst_atomics, 0); + EXPECT_EQ(f->suppressions, std::string("qwerty")); + EXPECT_EQ(f->print_suppressions, 0); + EXPECT_EQ(f->print_benign, 0); + EXPECT_EQ(f->exitcode, 111); + EXPECT_EQ(f->halt_on_error, 0); + EXPECT_EQ(f->atexit_sleep_ms, 222); + EXPECT_EQ(f->profile_memory, std::string("qqq")); + EXPECT_EQ(f->flush_memory_ms, 444); + EXPECT_EQ(f->flush_symbolizer_ms, 555); + EXPECT_EQ(f->memory_limit_mb, 666); + EXPECT_EQ(f->stop_on_start, 0); + EXPECT_EQ(f->running_on_valgrind, 0); + EXPECT_EQ(f->history_size, 5); + EXPECT_EQ(f->io_sync, 1); + + EXPECT_EQ(f->symbolize, 0); + EXPECT_EQ(f->external_symbolizer_path, std::string("asdfgh")); + EXPECT_EQ(f->strip_path_prefix, std::string("zxcvb")); + EXPECT_EQ(f->fast_unwind_on_fatal, 0); + EXPECT_EQ(f->fast_unwind_on_malloc, 0); + EXPECT_EQ(f->handle_ioctl, 0); + EXPECT_EQ(f->malloc_context_size, 777); + EXPECT_EQ(f->log_path, std::string("aaa")); + EXPECT_EQ(f->verbosity, 2); + EXPECT_EQ(f->detect_leaks, 0); + EXPECT_EQ(f->leak_check_at_exit, 0); + EXPECT_EQ(f->allocator_may_return_null, 0); + EXPECT_EQ(f->print_summary, 0); +} + +void VerifyOptions2(Flags *f) { + EXPECT_EQ(f->enable_annotations, true); + EXPECT_EQ(f->suppress_equal_stacks, true); + EXPECT_EQ(f->suppress_equal_addresses, true); + EXPECT_EQ(f->suppress_java, true); + EXPECT_EQ(f->report_bugs, true); + EXPECT_EQ(f->report_thread_leaks, true); + EXPECT_EQ(f->report_destroy_locked, true); + EXPECT_EQ(f->report_signal_unsafe, true); + EXPECT_EQ(f->report_atomic_races, true); + EXPECT_EQ(f->force_seq_cst_atomics, true); + EXPECT_EQ(f->suppressions, std::string("aaaaa")); + EXPECT_EQ(f->print_suppressions, true); + EXPECT_EQ(f->print_benign, true); + EXPECT_EQ(f->exitcode, 222); + EXPECT_EQ(f->halt_on_error, true); + EXPECT_EQ(f->atexit_sleep_ms, 123); + EXPECT_EQ(f->profile_memory, std::string("bbbbb")); + EXPECT_EQ(f->flush_memory_ms, 234); + EXPECT_EQ(f->flush_symbolizer_ms, 345); + EXPECT_EQ(f->memory_limit_mb, 456); + EXPECT_EQ(f->stop_on_start, true); + EXPECT_EQ(f->running_on_valgrind, true); + EXPECT_EQ(f->history_size, 6); + EXPECT_EQ(f->io_sync, 2); + + EXPECT_EQ(f->symbolize, true); + EXPECT_EQ(f->external_symbolizer_path, std::string("cccccc")); + EXPECT_EQ(f->strip_path_prefix, std::string("ddddddd")); + EXPECT_EQ(f->fast_unwind_on_fatal, true); + EXPECT_EQ(f->fast_unwind_on_malloc, true); + EXPECT_EQ(f->handle_ioctl, true); + EXPECT_EQ(f->malloc_context_size, 567); + EXPECT_EQ(f->log_path, std::string("eeeeeee")); + EXPECT_EQ(f->verbosity, 3); + EXPECT_EQ(f->detect_leaks, true); + EXPECT_EQ(f->leak_check_at_exit, true); + EXPECT_EQ(f->allocator_may_return_null, true); + EXPECT_EQ(f->print_summary, true); +} + +static const char *test_default_options; +extern "C" const char *__tsan_default_options() { + return test_default_options; +} + +TEST(Flags, ParseDefaultOptions) { + ScopedInRtl in_rtl; + Flags f; + + test_default_options = options1; + InitializeFlags(&f, ""); + VerifyOptions1(&f); + + test_default_options = options2; + InitializeFlags(&f, ""); + VerifyOptions2(&f); +} + +TEST(Flags, ParseEnvOptions) { + ScopedInRtl in_rtl; + Flags f; + + InitializeFlags(&f, options1); + VerifyOptions1(&f); + + InitializeFlags(&f, options2); + VerifyOptions2(&f); +} + +TEST(Flags, ParsePriority) { + ScopedInRtl in_rtl; + Flags f; + + test_default_options = options2; + InitializeFlags(&f, options1); + VerifyOptions1(&f); + + test_default_options = options1; + InitializeFlags(&f, options2); + VerifyOptions2(&f); +} + } // namespace __tsan -- GitLab