123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- //===-- 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
|