diff --git a/compiler-rt/lib/asan/asan_flags.cc b/compiler-rt/lib/asan/asan_flags.cc index d73e43370021..811007854e7d 100644 --- a/compiler-rt/lib/asan/asan_flags.cc +++ b/compiler-rt/lib/asan/asan_flags.cc @@ -98,9 +98,9 @@ void InitializeFlags(Flags *f) { VReport(1, "Parsed activation flags: %s\n", buf); } - if (common_flags()->help) { - parser.PrintFlagDescriptions(); - } + if (common_flags()->verbosity) ReportUnrecognizedFlags(); + + if (common_flags()->help) parser.PrintFlagDescriptions(); // Flag validation: if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) { diff --git a/compiler-rt/lib/lsan/lsan_common.cc b/compiler-rt/lib/lsan/lsan_common.cc index c005f46fc665..0f74a7ac2447 100644 --- a/compiler-rt/lib/lsan/lsan_common.cc +++ b/compiler-rt/lib/lsan/lsan_common.cc @@ -75,6 +75,8 @@ static void InitializeFlags(bool standalone) { const char *options = GetEnv("LSAN_OPTIONS"); parser.ParseString(options); + if (common_flags()->verbosity) ReportUnrecognizedFlags(); + if (!help_before && common_flags()->help) parser.PrintFlagDescriptions(); } diff --git a/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc index 81c623498a0a..e8aeb453950b 100644 --- a/compiler-rt/lib/msan/msan.cc +++ b/compiler-rt/lib/msan/msan.cc @@ -157,6 +157,8 @@ static void InitializeFlags(Flags *f, const char *options) { parser.ParseString(options); + if (common_flags()->verbosity) ReportUnrecognizedFlags(); + if (common_flags()->help) parser.PrintFlagDescriptions(); // Check flag values: diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc b/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc index 64b4f5392081..d125002daf4c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc @@ -22,6 +22,32 @@ namespace __sanitizer { LowLevelAllocator FlagParser::Alloc; +class UnknownFlags { + static const int kMaxUnknownFlags = 20; + const char *unknown_flags_[kMaxUnknownFlags]; + int n_unknown_flags_; + + public: + void Add(const char *name) { + CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); + unknown_flags_[n_unknown_flags_++] = name; + } + + void Report() { + if (!n_unknown_flags_) return; + Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); + for (int i = 0; i < n_unknown_flags_; ++i) + Printf(" %s\n", unknown_flags_[i]); + n_unknown_flags_ = 0; + } +}; + +UnknownFlags unknown_flags; + +void ReportUnrecognizedFlags() { + unknown_flags.Report(); +} + char *FlagParser::ll_strndup(const char *s, uptr n) { uptr len = internal_strnlen(s, n); char *s2 = (char*)Alloc.Allocate(len + 1); @@ -106,8 +132,9 @@ bool FlagParser::run_handler(const char *name, const char *value) { if (internal_strcmp(name, flags_[i].name) == 0) return flags_[i].handler->Parse(value); } - Printf("ERROR: Unknown flag: '%s'\n", name); - return false; + // Unrecognized flag. This is not a fatal error, we may print a warning later. + unknown_flags.Add(name); + return true; } void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h b/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h index b391cab4173c..87afb8238c01 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h @@ -114,6 +114,8 @@ static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, parser->RegisterHandler(name, fh, desc); } +void ReportUnrecognizedFlags(); + } // namespace __sanitizer #endif // SANITIZER_FLAG_REGISTRY_H diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc index 65adee07d1f7..3e5d8381ed3a 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -63,9 +63,14 @@ TEST(SanitizerCommon, IntFlags) { TestFlag(-11, "flag_name=0", 0); TestFlag(-11, "flag_name=42", 42); TestFlag(-11, "flag_name=-42", -42); + + // Unrecognized flags are ignored. + TestFlag(-11, "--flag_name=42", -11); + TestFlag(-11, "zzzzzzz=42", -11); + EXPECT_DEATH(TestFlag(-11, "flag_name", 0), "expected '='"); - EXPECT_DEATH(TestFlag(-11, "--flag_name=42", 0), - "Unknown flag: '--flag_name'"); + EXPECT_DEATH(TestFlag(-11, "flag_name=42U", 0), + "Invalid value for int option"); } TEST(SanitizerCommon, StrFlags) { diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/compiler-rt/lib/tsan/rtl/tsan_flags.cc index b99d92fc899b..c809ee77f63b 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc @@ -80,8 +80,9 @@ void InitializeFlags(Flags *f, const char *env) { f->report_signal_unsafe = false; } - if (common_flags()->help) - parser.PrintFlagDescriptions(); + if (common_flags()->verbosity) ReportUnrecognizedFlags(); + + if (common_flags()->help) parser.PrintFlagDescriptions(); if (f->history_size < 0 || f->history_size > 7) { Printf("ThreadSanitizer: incorrect value for history_size" diff --git a/compiler-rt/test/sanitizer_common/TestCases/options-invalid.cc b/compiler-rt/test/sanitizer_common/TestCases/options-invalid.cc index 940f1bbbf85b..3c261405c992 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/options-invalid.cc +++ b/compiler-rt/test/sanitizer_common/TestCases/options-invalid.cc @@ -1,7 +1,15 @@ // RUN: %clangxx -O0 %s -o %t -// RUN: %tool_options=invalid_option_name=10 not %run %t 2>&1 | FileCheck %s +// RUN: %tool_options=invalid_option_name=10,verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-V1 +// RUN: %tool_options=invalid_option_name=10 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-V0 + +#include int main() { + fprintf(stderr, "done\n"); } -// CHECK: Unknown flag{{.*}}invalid_option_name +// CHECK-V1: WARNING: found 1 unrecognized +// CHECK-V1: invalid_option_name +// CHECK-V0-NOT: WARNING: found 1 unrecognized +// CHECK-V0-NOT: invalid_option_name +// CHECK: done