[clang] Handle __declspec() attributes in using
[llvm-project.git] / compiler-rt / lib / sanitizer_common / sanitizer_flag_parser.cpp
blob9e274268bf2a613c40589820d939d99adc00dc7e
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.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_flag_parser.h"
15 #include "sanitizer_common.h"
16 #include "sanitizer_libc.h"
17 #include "sanitizer_flags.h"
18 #include "sanitizer_flag_parser.h"
20 namespace __sanitizer {
22 LowLevelAllocator FlagParser::Alloc;
24 class UnknownFlags {
25 static const int kMaxUnknownFlags = 20;
26 const char *unknown_flags_[kMaxUnknownFlags];
27 int n_unknown_flags_;
29 public:
30 void Add(const char *name) {
31 CHECK_LT(n_unknown_flags_, kMaxUnknownFlags);
32 unknown_flags_[n_unknown_flags_++] = name;
35 void Report() {
36 if (!n_unknown_flags_) return;
37 Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_);
38 for (int i = 0; i < n_unknown_flags_; ++i)
39 Printf(" %s\n", unknown_flags_[i]);
40 n_unknown_flags_ = 0;
44 UnknownFlags unknown_flags;
46 void ReportUnrecognizedFlags() {
47 unknown_flags.Report();
50 char *FlagParser::ll_strndup(const char *s, uptr n) {
51 uptr len = internal_strnlen(s, n);
52 char *s2 = (char*)Alloc.Allocate(len + 1);
53 internal_memcpy(s2, s, len);
54 s2[len] = 0;
55 return s2;
58 void FlagParser::PrintFlagDescriptions() {
59 char buffer[128];
60 buffer[sizeof(buffer) - 1] = '\0';
61 Printf("Available flags for %s:\n", SanitizerToolName);
62 for (int i = 0; i < n_flags_; ++i) {
63 bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer)));
64 CHECK_EQ(buffer[sizeof(buffer) - 1], '\0');
65 const char *truncation_str = truncated ? " Truncated" : "";
66 Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name,
67 flags_[i].desc, truncation_str, buffer);
71 void FlagParser::fatal_error(const char *err) {
72 Printf("%s: ERROR: %s\n", SanitizerToolName, err);
73 Die();
76 bool FlagParser::is_space(char c) {
77 return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' ||
78 c == '\r';
81 void FlagParser::skip_whitespace() {
82 while (is_space(buf_[pos_])) ++pos_;
85 void FlagParser::parse_flag(const char *env_option_name) {
86 uptr name_start = pos_;
87 while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_;
88 if (buf_[pos_] != '=') {
89 if (env_option_name) {
90 Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName,
91 env_option_name);
92 Die();
93 } else {
94 fatal_error("expected '='");
97 char *name = ll_strndup(buf_ + name_start, pos_ - name_start);
99 uptr value_start = ++pos_;
100 char *value;
101 if (buf_[pos_] == '\'' || buf_[pos_] == '"') {
102 char quote = buf_[pos_++];
103 while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_;
104 if (buf_[pos_] == 0) fatal_error("unterminated string");
105 value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1);
106 ++pos_; // consume the closing quote
107 } else {
108 while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_;
109 if (buf_[pos_] != 0 && !is_space(buf_[pos_]))
110 fatal_error("expected separator or eol");
111 value = ll_strndup(buf_ + value_start, pos_ - value_start);
114 bool res = run_handler(name, value);
115 if (!res) fatal_error("Flag parsing failed.");
118 void FlagParser::parse_flags(const char *env_option_name) {
119 while (true) {
120 skip_whitespace();
121 if (buf_[pos_] == 0) break;
122 parse_flag(env_option_name);
125 // Do a sanity check for certain flags.
126 if (common_flags_dont_use.malloc_context_size < 1)
127 common_flags_dont_use.malloc_context_size = 1;
130 void FlagParser::ParseStringFromEnv(const char *env_name) {
131 const char *env = GetEnv(env_name);
132 VPrintf(1, "%s: %s\n", env_name, env ? env : "<empty>");
133 ParseString(env, env_name);
136 void FlagParser::ParseString(const char *s, const char *env_option_name) {
137 if (!s) return;
138 // Backup current parser state to allow nested ParseString() calls.
139 const char *old_buf_ = buf_;
140 uptr old_pos_ = pos_;
141 buf_ = s;
142 pos_ = 0;
144 parse_flags(env_option_name);
146 buf_ = old_buf_;
147 pos_ = old_pos_;
150 bool FlagParser::ParseFile(const char *path, bool ignore_missing) {
151 static const uptr kMaxIncludeSize = 1 << 15;
152 char *data;
153 uptr data_mapped_size;
154 error_t err;
155 uptr len;
156 if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len,
157 Max(kMaxIncludeSize, GetPageSizeCached()), &err)) {
158 if (ignore_missing)
159 return true;
160 Printf("Failed to read options from '%s': error %d\n", path, err);
161 return false;
163 ParseString(data, path);
164 UnmapOrDie(data, data_mapped_size);
165 return true;
168 bool FlagParser::run_handler(const char *name, const char *value) {
169 for (int i = 0; i < n_flags_; ++i) {
170 if (internal_strcmp(name, flags_[i].name) == 0)
171 return flags_[i].handler->Parse(value);
173 // Unrecognized flag. This is not a fatal error, we may print a warning later.
174 unknown_flags.Add(name);
175 return true;
178 void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler,
179 const char *desc) {
180 CHECK_LT(n_flags_, kMaxFlags);
181 flags_[n_flags_].name = name;
182 flags_[n_flags_].desc = desc;
183 flags_[n_flags_].handler = handler;
184 ++n_flags_;
187 FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
188 flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags);
191 } // namespace __sanitizer