aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp
diff options
context:
space:
mode:
authornkozlovskiy <nmk@ydb.tech>2023-10-11 19:11:46 +0300
committernkozlovskiy <nmk@ydb.tech>2023-10-11 19:33:28 +0300
commit61b3971447e473726d6cdb23fc298e457b4d973c (patch)
treee2a2a864bb7717f7ae6138f6a3194a254dd2c7bb /contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp
parenta674dc57d88d43c2e8e90a6084d5d2c988e0402c (diff)
downloadydb-61b3971447e473726d6cdb23fc298e457b4d973c.tar.gz
add sanitizers dependencies
Diffstat (limited to 'contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp')
-rw-r--r--contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp b/contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp
new file mode 100644
index 0000000000..60234124e8
--- /dev/null
+++ b/contrib/libs/clang14-rt/lib/gwp_asan/optional/options_parser.cpp
@@ -0,0 +1,258 @@
+//===-- options_parser.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gwp_asan/optional/options_parser.h"
+#include "gwp_asan/optional/printf.h"
+#include "gwp_asan/utilities.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace {
+enum class OptionType : uint8_t {
+ OT_bool,
+ OT_int,
+};
+
+#define InvokeIfNonNull(Printf, ...) \
+ do { \
+ if (Printf) \
+ Printf(__VA_ARGS__); \
+ } while (0);
+
+class OptionParser {
+public:
+ explicit OptionParser(gwp_asan::Printf_t PrintfForWarnings)
+ : Printf(PrintfForWarnings) {}
+ void registerOption(const char *Name, const char *Desc, OptionType Type,
+ void *Var);
+ void parseString(const char *S);
+ void printOptionDescriptions();
+
+private:
+ // Calculate at compile-time how many options are available.
+#define GWP_ASAN_OPTION(...) +1
+ static constexpr size_t MaxOptions = 0
+#include "gwp_asan/options.inc"
+ ;
+#undef GWP_ASAN_OPTION
+
+ struct Option {
+ const char *Name;
+ const char *Desc;
+ OptionType Type;
+ void *Var;
+ } Options[MaxOptions];
+
+ size_t NumberOfOptions = 0;
+ const char *Buffer = nullptr;
+ uintptr_t Pos = 0;
+ gwp_asan::Printf_t Printf = nullptr;
+
+ void skipWhitespace();
+ void parseOptions();
+ bool parseOption();
+ bool setOptionToValue(const char *Name, const char *Value);
+};
+
+void OptionParser::printOptionDescriptions() {
+ InvokeIfNonNull(Printf, "GWP-ASan: Available options:\n");
+ for (size_t I = 0; I < NumberOfOptions; ++I)
+ InvokeIfNonNull(Printf, "\t%s\n\t\t- %s\n", Options[I].Name,
+ Options[I].Desc);
+}
+
+bool isSeparator(char C) {
+ return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||
+ C == '\r';
+}
+
+bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }
+
+void OptionParser::skipWhitespace() {
+ while (isSeparator(Buffer[Pos]))
+ ++Pos;
+}
+
+bool OptionParser::parseOption() {
+ const uintptr_t NameStart = Pos;
+ while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))
+ ++Pos;
+
+ const char *Name = Buffer + NameStart;
+ if (Buffer[Pos] != '=') {
+ InvokeIfNonNull(Printf, "GWP-ASan: Expected '=' when parsing option '%s'.",
+ Name);
+ return false;
+ }
+ const uintptr_t ValueStart = ++Pos;
+ const char *Value;
+ if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {
+ const char Quote = Buffer[Pos++];
+ while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)
+ ++Pos;
+ if (Buffer[Pos] == 0) {
+ InvokeIfNonNull(Printf, "GWP-ASan: Unterminated string in option '%s'.",
+ Name);
+ return false;
+ }
+ Value = Buffer + ValueStart + 1;
+ ++Pos; // consume the closing quote
+ } else {
+ while (!isSeparatorOrNull(Buffer[Pos]))
+ ++Pos;
+ Value = Buffer + ValueStart;
+ }
+
+ return setOptionToValue(Name, Value);
+}
+
+void OptionParser::parseOptions() {
+ while (true) {
+ skipWhitespace();
+ if (Buffer[Pos] == 0)
+ break;
+ if (!parseOption()) {
+ InvokeIfNonNull(Printf, "GWP-ASan: Options parsing failed.\n");
+ return;
+ }
+ }
+}
+
+void OptionParser::parseString(const char *S) {
+ if (!S)
+ return;
+ Buffer = S;
+ Pos = 0;
+ parseOptions();
+}
+
+bool parseBool(const char *Value, bool *b) {
+ if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||
+ strncmp(Value, "false", 5) == 0) {
+ *b = false;
+ return true;
+ }
+ if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||
+ strncmp(Value, "true", 4) == 0) {
+ *b = true;
+ return true;
+ }
+ return false;
+}
+
+bool OptionParser::setOptionToValue(const char *Name, const char *Value) {
+ for (size_t I = 0; I < NumberOfOptions; ++I) {
+ const uintptr_t Len = strlen(Options[I].Name);
+ if (strncmp(Name, Options[I].Name, Len) != 0 || Name[Len] != '=')
+ continue;
+ bool Ok = false;
+ switch (Options[I].Type) {
+ case OptionType::OT_bool:
+ Ok = parseBool(Value, reinterpret_cast<bool *>(Options[I].Var));
+ if (!Ok)
+ InvokeIfNonNull(
+ Printf, "GWP-ASan: Invalid boolean value '%s' for option '%s'.\n",
+ Value, Options[I].Name);
+ break;
+ case OptionType::OT_int:
+ char *ValueEnd;
+ *reinterpret_cast<int *>(Options[I].Var) =
+ static_cast<int>(strtol(Value, &ValueEnd, 10));
+ Ok =
+ *ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);
+ if (!Ok)
+ InvokeIfNonNull(
+ Printf, "GWP-ASan: Invalid integer value '%s' for option '%s'.\n",
+ Value, Options[I].Name);
+ break;
+ }
+ return Ok;
+ }
+
+ InvokeIfNonNull(Printf, "GWP-ASan: Unknown option '%s'.", Name);
+ return true;
+}
+
+void OptionParser::registerOption(const char *Name, const char *Desc,
+ OptionType Type, void *Var) {
+ assert(NumberOfOptions < MaxOptions &&
+ "GWP-ASan Error: Ran out of space for options.\n");
+ Options[NumberOfOptions].Name = Name;
+ Options[NumberOfOptions].Desc = Desc;
+ Options[NumberOfOptions].Type = Type;
+ Options[NumberOfOptions].Var = Var;
+ ++NumberOfOptions;
+}
+
+void registerGwpAsanOptions(OptionParser *parser,
+ gwp_asan::options::Options *o) {
+#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
+ parser->registerOption(#Name, Description, OptionType::OT_##Type, &o->Name);
+#include "gwp_asan/options.inc"
+#undef GWP_ASAN_OPTION
+}
+
+const char *getGwpAsanDefaultOptions() {
+ return (__gwp_asan_default_options) ? __gwp_asan_default_options() : "";
+}
+
+gwp_asan::options::Options *getOptionsInternal() {
+ static gwp_asan::options::Options GwpAsanOptions;
+ return &GwpAsanOptions;
+}
+} // anonymous namespace
+
+namespace gwp_asan {
+namespace options {
+
+void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings) {
+ Options *o = getOptionsInternal();
+ o->setDefaults();
+
+ OptionParser Parser(PrintfForWarnings);
+ registerGwpAsanOptions(&Parser, o);
+
+ // Override from the weak function definition in this executable.
+ Parser.parseString(getGwpAsanDefaultOptions());
+
+ // Override from the provided options string.
+ Parser.parseString(OptionsStr);
+
+ if (o->help)
+ Parser.printOptionDescriptions();
+
+ if (!o->Enabled)
+ return;
+
+ if (o->MaxSimultaneousAllocations <= 0) {
+ InvokeIfNonNull(
+ PrintfForWarnings,
+ "GWP-ASan ERROR: MaxSimultaneousAllocations must be > 0 when GWP-ASan "
+ "is enabled.\n");
+ o->Enabled = false;
+ }
+ if (o->SampleRate <= 0) {
+ InvokeIfNonNull(
+ PrintfForWarnings,
+ "GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n");
+ o->Enabled = false;
+ }
+}
+
+void initOptions(Printf_t PrintfForWarnings) {
+ initOptions(getenv("GWP_ASAN_OPTIONS"), PrintfForWarnings);
+}
+
+Options &getOptions() { return *getOptionsInternal(); }
+
+} // namespace options
+} // namespace gwp_asan