Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/gwp_asan/optional/options_parser.cpp
35271 views
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
//===----------------------------------------------------------------------===//
8
9
#include "gwp_asan/optional/options_parser.h"
10
#include "gwp_asan/optional/printf.h"
11
#include "gwp_asan/utilities.h"
12
13
#include <assert.h>
14
#include <stdarg.h>
15
#include <stdint.h>
16
#include <stdlib.h>
17
#include <string.h>
18
19
namespace {
20
enum class OptionType : uint8_t {
21
OT_bool,
22
OT_int,
23
};
24
25
#define InvokeIfNonNull(Printf, ...) \
26
do { \
27
if (Printf) \
28
Printf(__VA_ARGS__); \
29
} while (0);
30
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();
39
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"
45
;
46
#undef GWP_ASAN_OPTION
47
48
struct Option {
49
const char *Name;
50
const char *Desc;
51
OptionType Type;
52
void *Var;
53
} Options[MaxOptions];
54
55
size_t NumberOfOptions = 0;
56
const char *Buffer = nullptr;
57
uintptr_t Pos = 0;
58
gwp_asan::Printf_t Printf = nullptr;
59
60
void skipWhitespace();
61
void parseOptions();
62
bool parseOption();
63
bool setOptionToValue(const char *Name, const char *Value);
64
};
65
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);
71
}
72
73
bool isSeparator(char C) {
74
return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
75
C == '\r';
76
}
77
78
bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
79
80
void OptionParser::skipWhitespace() {
81
while (isSeparator(Buffer[Pos]))
82
++Pos;
83
}
84
85
bool OptionParser::parseOption() {
86
const uintptr_t NameStart = Pos;
87
while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
88
++Pos;
89
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;
95
}
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;
106
}
107
Value = Buffer + ValueStart + 1;
108
++Pos; // consume the closing quote
109
} else {
110
while (!isSeparatorOrNull(Buffer[Pos]))
111
++Pos;
112
Value = Buffer + ValueStart;
113
}
114
115
return setOptionToValue(Name, Value);
116
}
117
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;
126
}
127
}
128
}
129
130
void OptionParser::parseString(const char *S) {
131
if (!S)
132
return;
133
Buffer = S;
134
Pos = 0;
135
parseOptions();
136
}
137
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;
143
}
144
if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
145
strncmp(Value, "true", 4) == 0) {
146
*b = true;
147
return true;
148
}
149
return false;
150
}
151
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;
177
}
178
return Ok;
179
}
180
181
InvokeIfNonNull(Printf, "GWP-ASan: Unknown option '%s'.", Name);
182
return true;
183
}
184
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;
194
}
195
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
202
}
203
204
const char *getGwpAsanDefaultOptions() {
205
return (__gwp_asan_default_options) ? __gwp_asan_default_options() : "";
206
}
207
208
gwp_asan::options::Options *getOptionsInternal() {
209
static gwp_asan::options::Options GwpAsanOptions;
210
return &GwpAsanOptions;
211
}
212
} // anonymous namespace
213
214
namespace gwp_asan {
215
namespace options {
216
217
void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings) {
218
Options *o = getOptionsInternal();
219
o->setDefaults();
220
221
OptionParser Parser(PrintfForWarnings);
222
registerGwpAsanOptions(&Parser, o);
223
224
// Override from the weak function definition in this executable.
225
Parser.parseString(getGwpAsanDefaultOptions());
226
227
// Override from the provided options string.
228
Parser.parseString(OptionsStr);
229
230
if (o->help)
231
Parser.printOptionDescriptions();
232
233
if (!o->Enabled)
234
return;
235
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;
242
}
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;
248
}
249
}
250
251
void initOptions(Printf_t PrintfForWarnings) {
252
initOptions(getenv("GWP_ASAN_OPTIONS"), PrintfForWarnings);
253
}
254
255
Options &getOptions() { return *getOptionsInternal(); }
256
257
} // namespace options
258
} // namespace gwp_asan
259
260