Index: compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h +++ compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h @@ -121,7 +121,7 @@ private: void fatal_error(const char *err); - bool is_space(char c); + bool is_space(); void skip_whitespace(); void parse_flags(); void parse_flag(); Index: compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.cc @@ -67,18 +67,27 @@ Die(); } -bool FlagParser::is_space(char c) { - return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || - c == '\r'; +bool FlagParser::is_space() { + char c = buf_[pos_]; + if (c == ' ' || c == ',' || c == '\n' || c == '\t' || c == '\r') + return true; + + // Treat ':' as an option separator unless it is immediately followed by a + // path separator. This avoids common portability issues when an unquoted + // Windows path is used, as in 'symbolizer_path=C:/foo/llvm-symbolizer.exe'. + // Since no option names should start with / or \, it should be unambiguous. + if (c == ':') + return buf_[pos_ + 1] != '\\' && buf_[pos_ + 1] != '/'; + return false; } void FlagParser::skip_whitespace() { - while (is_space(buf_[pos_])) ++pos_; + while (is_space()) ++pos_; } void FlagParser::parse_flag() { uptr name_start = pos_; - while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; + while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space()) ++pos_; if (buf_[pos_] != '=') fatal_error("expected '='"); char *name = ll_strndup(buf_ + name_start, pos_ - name_start); @@ -91,8 +100,8 @@ value = ll_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_])) + while (buf_[pos_] != 0 && !is_space()) ++pos_; + if (buf_[pos_] != 0 && !is_space()) fatal_error("expected separator or eol"); value = ll_strndup(buf_ + value_start, pos_ - value_start); } Index: compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc =================================================================== --- compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ compiler-rt/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -177,4 +177,17 @@ EXPECT_STREQ("path/two", cf.log_path); } +TEST(SanitizerCommon, WindowsPath) { + FlagParser parser; + const char *p1 = ""; + const char *p2 = ""; + RegisterFlag(&parser, "path1", kFlagDesc, &p1); + RegisterFlag(&parser, "path2", kFlagDesc, &p2); + parser.ParseString("path1=C:/win/path.exe:path2=C:\\win\\path.exe"); + ReportUnrecognizedFlags(); + + EXPECT_STREQ(p1, "C:/win/path.exe"); + EXPECT_STREQ(p2, "C:\\win\\path.exe"); +} + } // namespace __sanitizer