Index: lib/asan/asan_activation.cc =================================================================== --- lib/asan/asan_activation.cc +++ lib/asan/asan_activation.cc @@ -38,7 +38,7 @@ #undef ASAN_ACTIVATION_FLAG #undef COMMON_ACTIVATION_FLAG - RegisterIncludeFlag(parser, cf); + RegisterIncludeFlags(parser, cf); } void OverrideFromActivationFlags() { Index: lib/sanitizer_common/sanitizer_flag_parser.h =================================================================== --- lib/sanitizer_common/sanitizer_flag_parser.h +++ lib/sanitizer_common/sanitizer_flag_parser.h @@ -93,6 +93,7 @@ void RegisterHandler(const char *name, FlagHandlerBase *handler, const char *desc); void ParseString(const char *s); + bool ParseFile(const char *path, bool ignore_missing); void PrintFlagDescriptions(); static LowLevelAllocator Alloc; Index: lib/sanitizer_common/sanitizer_flag_parser.cc =================================================================== --- lib/sanitizer_common/sanitizer_flag_parser.cc +++ lib/sanitizer_common/sanitizer_flag_parser.cc @@ -127,6 +127,24 @@ pos_ = old_pos_; } +bool FlagParser::ParseFile(const char *path, bool ignore_missing) { + static const uptr kMaxIncludeSize = 1 << 15; + char *data; + uptr data_mapped_size; + error_t err; + uptr len = ReadFileToBuffer(path, &data, &data_mapped_size, + Max(kMaxIncludeSize, GetPageSizeCached()), &err); + if (!len) { + if (ignore_missing) + return true; + Printf("Failed to read options from '%s': error %d\n", path, err); + return false; + } + ParseString(data); + UnmapOrDie(data, data_mapped_size); + return true; +} + 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) Index: lib/sanitizer_common/sanitizer_flags.h =================================================================== --- lib/sanitizer_common/sanitizer_flags.h +++ lib/sanitizer_common/sanitizer_flags.h @@ -49,7 +49,7 @@ class FlagParser; void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf = &common_flags_dont_use); -void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf); +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf); } // namespace __sanitizer #endif // SANITIZER_FLAGS_H Index: lib/sanitizer_common/sanitizer_flags.cc =================================================================== --- lib/sanitizer_common/sanitizer_flags.cc +++ lib/sanitizer_common/sanitizer_flags.cc @@ -46,33 +46,27 @@ } class FlagHandlerInclude : public FlagHandlerBase { - static const uptr kMaxIncludeSize = 1 << 15; FlagParser *parser_; + bool ignore_missing_; public: - explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {} + explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) + : parser_(parser), ignore_missing_(ignore_missing) {} bool Parse(const char *value) final { - char *data; - uptr data_mapped_size; - error_t err; - uptr len = - ReadFileToBuffer(value, &data, &data_mapped_size, - Max(kMaxIncludeSize, GetPageSizeCached()), &err); - if (!len) { - Printf("Failed to read options from '%s': error %d\n", value, err); - return false; - } - parser_->ParseString(data); - UnmapOrDie(data, data_mapped_size); - return true; + return parser_->ParseFile(value, ignore_missing_); } }; -void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf) { +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { FlagHandlerInclude *fh_include = - new (FlagParser::Alloc) FlagHandlerInclude(parser); // NOLINT + new (FlagParser::Alloc) FlagHandlerInclude(parser, false); // NOLINT parser->RegisterHandler("include", fh_include, "read more options from the given file"); + FlagHandlerInclude *fh_include_ignore_missing = + new (FlagParser::Alloc) FlagHandlerInclude(parser, true); // NOLINT + parser->RegisterHandler( + "include?", fh_include_ignore_missing, + "read more options from the given file (if it exists)"); } void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { @@ -81,7 +75,7 @@ #include "sanitizer_flags.inc" #undef COMMON_FLAG - RegisterIncludeFlag(parser, cf); + RegisterIncludeFlags(parser, cf); } } // namespace __sanitizer Index: test/sanitizer_common/TestCases/options-include.cc =================================================================== --- test/sanitizer_common/TestCases/options-include.cc +++ test/sanitizer_common/TestCases/options-include.cc @@ -4,11 +4,13 @@ // RUN: cat %t.options1.txt // RUN: cat %t.options2.txt // RUN: %tool_options="help=0:include='%t.options1.txt'" %run %t 2>&1 | tee %t.out -// RUN: FileCheck %s --check-prefix=CHECK-VERBOSITY1 <%t.out +// RUN: FileCheck %s --check-prefix=CHECK-WITH-HELP --check-prefix=CHECK-FOUND <%t.out // RUN: %tool_options="include='%t.options1.txt',help=0" %run %t 2>&1 | tee %t.out -// RUN: FileCheck %s --check-prefix=CHECK-VERBOSITY0 <%t.out +// RUN: FileCheck %s --check-prefix=CHECK-WITHOUT-HELP --check-prefix=CHECK-FOUND <%t.out // RUN: %tool_options="include='%t.options-not-found.txt',help=1" not %run %t 2>&1 | tee %t.out // RUN: FileCheck %s --check-prefix=CHECK-NOT-FOUND < %t.out +// RUN: %tool_options="include?='%t.options-not-found.txt',help=1" %run %t 2>&1 | tee %t.out +// RUN: FileCheck %s --check-prefix=CHECK-WITH-HELP --check-prefix=CHECK-FOUND < %t.out #include @@ -16,6 +18,7 @@ fprintf(stderr, "done\n"); } -// CHECK-VERBOSITY1: Available flags for -// CHECK-VERBOSITY0-NOT: Available flags for +// CHECK-WITH-HELP: Available flags for +// CHECK-WITHOUT-HELP-NOT: Available flags for +// CHECK-FOUND-NOT: Failed to read options from // CHECK-NOT-FOUND: Failed to read options from