sanitizer_flag_parser.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. //===-- sanitizer_flag_parser.cpp -----------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "sanitizer_flag_parser.h"
  13. #include "sanitizer_common.h"
  14. #include "sanitizer_libc.h"
  15. #include "sanitizer_flags.h"
  16. #include "sanitizer_flag_parser.h"
  17. namespace __sanitizer {
  18. LowLevelAllocator FlagParser::Alloc;
  19. class UnknownFlags {
  20. static const int kMaxUnknownFlags = 20;
  21. const char *unknown_flags_[kMaxUnknownFlags];
  22. int n_unknown_flags_;
  23. public:
  24. void Add(const char *name) {
  25. CHECK_LT(n_unknown_flags_, kMaxUnknownFlags);
  26. unknown_flags_[n_unknown_flags_++] = name;
  27. }
  28. void Report() {
  29. if (!n_unknown_flags_) return;
  30. Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_);
  31. for (int i = 0; i < n_unknown_flags_; ++i)
  32. Printf(" %s\n", unknown_flags_[i]);
  33. n_unknown_flags_ = 0;
  34. }
  35. };
  36. UnknownFlags unknown_flags;
  37. void ReportUnrecognizedFlags() {
  38. unknown_flags.Report();
  39. }
  40. char *FlagParser::ll_strndup(const char *s, uptr n) {
  41. uptr len = internal_strnlen(s, n);
  42. char *s2 = (char*)Alloc.Allocate(len + 1);
  43. internal_memcpy(s2, s, len);
  44. s2[len] = 0;
  45. return s2;
  46. }
  47. void FlagParser::PrintFlagDescriptions() {
  48. char buffer[128];
  49. buffer[sizeof(buffer) - 1] = '\0';
  50. Printf("Available flags for %s:\n", SanitizerToolName);
  51. for (int i = 0; i < n_flags_; ++i) {
  52. bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer)));
  53. CHECK_EQ(buffer[sizeof(buffer) - 1], '\0');
  54. const char *truncation_str = truncated ? " Truncated" : "";
  55. Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name,
  56. flags_[i].desc, truncation_str, buffer);
  57. }
  58. }
  59. void FlagParser::fatal_error(const char *err) {
  60. Printf("%s: ERROR: %s\n", SanitizerToolName, err);
  61. Die();
  62. }
  63. bool FlagParser::is_space(char c) {
  64. return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' ||
  65. c == '\r';
  66. }
  67. void FlagParser::skip_whitespace() {
  68. while (is_space(buf_[pos_])) ++pos_;
  69. }
  70. void FlagParser::parse_flag(const char *env_option_name) {
  71. uptr name_start = pos_;
  72. while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_;
  73. if (buf_[pos_] != '=') {
  74. if (env_option_name) {
  75. Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName,
  76. env_option_name);
  77. Die();
  78. } else {
  79. fatal_error("expected '='");
  80. }
  81. }
  82. char *name = ll_strndup(buf_ + name_start, pos_ - name_start);
  83. uptr value_start = ++pos_;
  84. char *value;
  85. if (buf_[pos_] == '\'' || buf_[pos_] == '"') {
  86. char quote = buf_[pos_++];
  87. while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_;
  88. if (buf_[pos_] == 0) fatal_error("unterminated string");
  89. value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1);
  90. ++pos_; // consume the closing quote
  91. } else {
  92. while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_;
  93. if (buf_[pos_] != 0 && !is_space(buf_[pos_]))
  94. fatal_error("expected separator or eol");
  95. value = ll_strndup(buf_ + value_start, pos_ - value_start);
  96. }
  97. bool res = run_handler(name, value);
  98. if (!res) fatal_error("Flag parsing failed.");
  99. }
  100. void FlagParser::parse_flags(const char *env_option_name) {
  101. while (true) {
  102. skip_whitespace();
  103. if (buf_[pos_] == 0) break;
  104. parse_flag(env_option_name);
  105. }
  106. // Do a sanity check for certain flags.
  107. if (common_flags_dont_use.malloc_context_size < 1)
  108. common_flags_dont_use.malloc_context_size = 1;
  109. }
  110. void FlagParser::ParseStringFromEnv(const char *env_name) {
  111. const char *env = GetEnv(env_name);
  112. VPrintf(1, "%s: %s\n", env_name, env ? env : "<empty>");
  113. ParseString(env, env_name);
  114. }
  115. void FlagParser::ParseString(const char *s, const char *env_option_name) {
  116. if (!s) return;
  117. // Backup current parser state to allow nested ParseString() calls.
  118. const char *old_buf_ = buf_;
  119. uptr old_pos_ = pos_;
  120. buf_ = s;
  121. pos_ = 0;
  122. parse_flags(env_option_name);
  123. buf_ = old_buf_;
  124. pos_ = old_pos_;
  125. }
  126. bool FlagParser::ParseFile(const char *path, bool ignore_missing) {
  127. static const uptr kMaxIncludeSize = 1 << 15;
  128. char *data;
  129. uptr data_mapped_size;
  130. error_t err;
  131. uptr len;
  132. if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len,
  133. Max(kMaxIncludeSize, GetPageSizeCached()), &err)) {
  134. if (ignore_missing)
  135. return true;
  136. Printf("Failed to read options from '%s': error %d\n", path, err);
  137. return false;
  138. }
  139. ParseString(data, path);
  140. UnmapOrDie(data, data_mapped_size);
  141. return true;
  142. }
  143. bool FlagParser::run_handler(const char *name, const char *value) {
  144. for (int i = 0; i < n_flags_; ++i) {
  145. if (internal_strcmp(name, flags_[i].name) == 0)
  146. return flags_[i].handler->Parse(value);
  147. }
  148. // Unrecognized flag. This is not a fatal error, we may print a warning later.
  149. unknown_flags.Add(name);
  150. return true;
  151. }
  152. void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler,
  153. const char *desc) {
  154. CHECK_LT(n_flags_, kMaxFlags);
  155. flags_[n_flags_].name = name;
  156. flags_[n_flags_].desc = desc;
  157. flags_[n_flags_].handler = handler;
  158. ++n_flags_;
  159. }
  160. FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
  161. flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags);
  162. }
  163. } // namespace __sanitizer