[clang] Handle __declspec() attributes in using
[llvm-project.git] / compiler-rt / lib / gwp_asan / optional / options_parser.cpp
blob60234124e8ede9306059cc4e4e008fa880e20f77
1 //===-- options_parser.cpp --------------------------------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
9 #include "gwp_asan/optional/options_parser.h"
10 #include "gwp_asan/optional/printf.h"
11 #include "gwp_asan/utilities.h"
13 #include <assert.h>
14 #include <stdarg.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
19 namespace {
20 enum class OptionType : uint8_t {
21 OT_bool,
22 OT_int,
25 #define InvokeIfNonNull(Printf, ...) \
26 do { \
27 if (Printf) \
28 Printf(__VA_ARGS__); \
29 } while (0);
31 class OptionParser {
32 public:
33 explicit OptionParser(gwp_asan::Printf_t PrintfForWarnings)
34 : Printf(PrintfForWarnings) {}
35 void registerOption(const char *Name, const char *Desc, OptionType Type,
36 void *Var);
37 void parseString(const char *S);
38 void printOptionDescriptions();
40 private:
41 // Calculate at compile-time how many options are available.
42 #define GWP_ASAN_OPTION(...) +1
43 static constexpr size_t MaxOptions = 0
44 #include "gwp_asan/options.inc"
46 #undef GWP_ASAN_OPTION
48 struct Option {
49 const char *Name;
50 const char *Desc;
51 OptionType Type;
52 void *Var;
53 } Options[MaxOptions];
55 size_t NumberOfOptions = 0;
56 const char *Buffer = nullptr;
57 uintptr_t Pos = 0;
58 gwp_asan::Printf_t Printf = nullptr;
60 void skipWhitespace();
61 void parseOptions();
62 bool parseOption();
63 bool setOptionToValue(const char *Name, const char *Value);
66 void OptionParser::printOptionDescriptions() {
67 InvokeIfNonNull(Printf, "GWP-ASan: Available options:\n");
68 for (size_t I = 0; I < NumberOfOptions; ++I)
69 InvokeIfNonNull(Printf, "\t%s\n\t\t- %s\n", Options[I].Name,
70 Options[I].Desc);
73 bool isSeparator(char C) {
74 return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
75 C == '\r';
78 bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
80 void OptionParser::skipWhitespace() {
81 while (isSeparator(Buffer[Pos]))
82 ++Pos;
85 bool OptionParser::parseOption() {
86 const uintptr_t NameStart = Pos;
87 while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
88 ++Pos;
90 const char *Name = Buffer + NameStart;
91 if (Buffer[Pos] != '=') {
92 InvokeIfNonNull(Printf, "GWP-ASan: Expected '=' when parsing option '%s'.",
93 Name);
94 return false;
96 const uintptr_t ValueStart = ++Pos;
97 const char *Value;
98 if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
99 const char Quote = Buffer[Pos++];
100 while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
101 ++Pos;
102 if (Buffer[Pos] == 0) {
103 InvokeIfNonNull(Printf, "GWP-ASan: Unterminated string in option '%s'.",
104 Name);
105 return false;
107 Value = Buffer + ValueStart + 1;
108 ++Pos; // consume the closing quote
109 } else {
110 while (!isSeparatorOrNull(Buffer[Pos]))
111 ++Pos;
112 Value = Buffer + ValueStart;
115 return setOptionToValue(Name, Value);
118 void OptionParser::parseOptions() {
119 while (true) {
120 skipWhitespace();
121 if (Buffer[Pos] == 0)
122 break;
123 if (!parseOption()) {
124 InvokeIfNonNull(Printf, "GWP-ASan: Options parsing failed.\n");
125 return;
130 void OptionParser::parseString(const char *S) {
131 if (!S)
132 return;
133 Buffer = S;
134 Pos = 0;
135 parseOptions();
138 bool parseBool(const char *Value, bool *b) {
139 if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
140 strncmp(Value, "false", 5) == 0) {
141 *b = false;
142 return true;
144 if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
145 strncmp(Value, "true", 4) == 0) {
146 *b = true;
147 return true;
149 return false;
152 bool OptionParser::setOptionToValue(const char *Name, const char *Value) {
153 for (size_t I = 0; I < NumberOfOptions; ++I) {
154 const uintptr_t Len = strlen(Options[I].Name);
155 if (strncmp(Name, Options[I].Name, Len) != 0 || Name[Len] != '=')
156 continue;
157 bool Ok = false;
158 switch (Options[I].Type) {
159 case OptionType::OT_bool:
160 Ok = parseBool(Value, reinterpret_cast<bool *>(Options[I].Var));
161 if (!Ok)
162 InvokeIfNonNull(
163 Printf, "GWP-ASan: Invalid boolean value '%s' for option '%s'.\n",
164 Value, Options[I].Name);
165 break;
166 case OptionType::OT_int:
167 char *ValueEnd;
168 *reinterpret_cast<int *>(Options[I].Var) =
169 static_cast<int>(strtol(Value, &ValueEnd, 10));
170 Ok =
171 *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
172 if (!Ok)
173 InvokeIfNonNull(
174 Printf, "GWP-ASan: Invalid integer value '%s' for option '%s'.\n",
175 Value, Options[I].Name);
176 break;
178 return Ok;
181 InvokeIfNonNull(Printf, "GWP-ASan: Unknown option '%s'.", Name);
182 return true;
185 void OptionParser::registerOption(const char *Name, const char *Desc,
186 OptionType Type, void *Var) {
187 assert(NumberOfOptions < MaxOptions &&
188 "GWP-ASan Error: Ran out of space for options.\n");
189 Options[NumberOfOptions].Name = Name;
190 Options[NumberOfOptions].Desc = Desc;
191 Options[NumberOfOptions].Type = Type;
192 Options[NumberOfOptions].Var = Var;
193 ++NumberOfOptions;
196 void registerGwpAsanOptions(OptionParser *parser,
197 gwp_asan::options::Options *o) {
198 #define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
199 parser->registerOption(#Name, Description, OptionType::OT_##Type, &o->Name);
200 #include "gwp_asan/options.inc"
201 #undef GWP_ASAN_OPTION
204 const char *getGwpAsanDefaultOptions() {
205 return (__gwp_asan_default_options) ? __gwp_asan_default_options() : "";
208 gwp_asan::options::Options *getOptionsInternal() {
209 static gwp_asan::options::Options GwpAsanOptions;
210 return &GwpAsanOptions;
212 } // anonymous namespace
214 namespace gwp_asan {
215 namespace options {
217 void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings) {
218 Options *o = getOptionsInternal();
219 o->setDefaults();
221 OptionParser Parser(PrintfForWarnings);
222 registerGwpAsanOptions(&Parser, o);
224 // Override from the weak function definition in this executable.
225 Parser.parseString(getGwpAsanDefaultOptions());
227 // Override from the provided options string.
228 Parser.parseString(OptionsStr);
230 if (o->help)
231 Parser.printOptionDescriptions();
233 if (!o->Enabled)
234 return;
236 if (o->MaxSimultaneousAllocations <= 0) {
237 InvokeIfNonNull(
238 PrintfForWarnings,
239 "GWP-ASan ERROR: MaxSimultaneousAllocations must be > 0 when GWP-ASan "
240 "is enabled.\n");
241 o->Enabled = false;
243 if (o->SampleRate <= 0) {
244 InvokeIfNonNull(
245 PrintfForWarnings,
246 "GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n");
247 o->Enabled = false;
251 void initOptions(Printf_t PrintfForWarnings) {
252 initOptions(getenv("GWP_ASAN_OPTIONS"), PrintfForWarnings);
255 Options &getOptions() { return *getOptionsInternal(); }
257 } // namespace options
258 } // namespace gwp_asan