Path: blob/main/contrib/llvm-project/compiler-rt/lib/gwp_asan/optional/options_parser.cpp
35271 views
//===-- options_parser.cpp --------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "gwp_asan/optional/options_parser.h"9#include "gwp_asan/optional/printf.h"10#include "gwp_asan/utilities.h"1112#include <assert.h>13#include <stdarg.h>14#include <stdint.h>15#include <stdlib.h>16#include <string.h>1718namespace {19enum class OptionType : uint8_t {20OT_bool,21OT_int,22};2324#define InvokeIfNonNull(Printf, ...) \25do { \26if (Printf) \27Printf(__VA_ARGS__); \28} while (0);2930class OptionParser {31public:32explicit OptionParser(gwp_asan::Printf_t PrintfForWarnings)33: Printf(PrintfForWarnings) {}34void registerOption(const char *Name, const char *Desc, OptionType Type,35void *Var);36void parseString(const char *S);37void printOptionDescriptions();3839private:40// Calculate at compile-time how many options are available.41#define GWP_ASAN_OPTION(...) +142static constexpr size_t MaxOptions = 043#include "gwp_asan/options.inc"44;45#undef GWP_ASAN_OPTION4647struct Option {48const char *Name;49const char *Desc;50OptionType Type;51void *Var;52} Options[MaxOptions];5354size_t NumberOfOptions = 0;55const char *Buffer = nullptr;56uintptr_t Pos = 0;57gwp_asan::Printf_t Printf = nullptr;5859void skipWhitespace();60void parseOptions();61bool parseOption();62bool setOptionToValue(const char *Name, const char *Value);63};6465void OptionParser::printOptionDescriptions() {66InvokeIfNonNull(Printf, "GWP-ASan: Available options:\n");67for (size_t I = 0; I < NumberOfOptions; ++I)68InvokeIfNonNull(Printf, "\t%s\n\t\t- %s\n", Options[I].Name,69Options[I].Desc);70}7172bool isSeparator(char C) {73return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||74C == '\r';75}7677bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }7879void OptionParser::skipWhitespace() {80while (isSeparator(Buffer[Pos]))81++Pos;82}8384bool OptionParser::parseOption() {85const uintptr_t NameStart = Pos;86while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))87++Pos;8889const char *Name = Buffer + NameStart;90if (Buffer[Pos] != '=') {91InvokeIfNonNull(Printf, "GWP-ASan: Expected '=' when parsing option '%s'.",92Name);93return false;94}95const uintptr_t ValueStart = ++Pos;96const char *Value;97if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {98const char Quote = Buffer[Pos++];99while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)100++Pos;101if (Buffer[Pos] == 0) {102InvokeIfNonNull(Printf, "GWP-ASan: Unterminated string in option '%s'.",103Name);104return false;105}106Value = Buffer + ValueStart + 1;107++Pos; // consume the closing quote108} else {109while (!isSeparatorOrNull(Buffer[Pos]))110++Pos;111Value = Buffer + ValueStart;112}113114return setOptionToValue(Name, Value);115}116117void OptionParser::parseOptions() {118while (true) {119skipWhitespace();120if (Buffer[Pos] == 0)121break;122if (!parseOption()) {123InvokeIfNonNull(Printf, "GWP-ASan: Options parsing failed.\n");124return;125}126}127}128129void OptionParser::parseString(const char *S) {130if (!S)131return;132Buffer = S;133Pos = 0;134parseOptions();135}136137bool parseBool(const char *Value, bool *b) {138if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||139strncmp(Value, "false", 5) == 0) {140*b = false;141return true;142}143if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||144strncmp(Value, "true", 4) == 0) {145*b = true;146return true;147}148return false;149}150151bool OptionParser::setOptionToValue(const char *Name, const char *Value) {152for (size_t I = 0; I < NumberOfOptions; ++I) {153const uintptr_t Len = strlen(Options[I].Name);154if (strncmp(Name, Options[I].Name, Len) != 0 || Name[Len] != '=')155continue;156bool Ok = false;157switch (Options[I].Type) {158case OptionType::OT_bool:159Ok = parseBool(Value, reinterpret_cast<bool *>(Options[I].Var));160if (!Ok)161InvokeIfNonNull(162Printf, "GWP-ASan: Invalid boolean value '%s' for option '%s'.\n",163Value, Options[I].Name);164break;165case OptionType::OT_int:166char *ValueEnd;167*reinterpret_cast<int *>(Options[I].Var) =168static_cast<int>(strtol(Value, &ValueEnd, 10));169Ok =170*ValueEnd == '"' || *ValueEnd == '\'' || isSeparatorOrNull(*ValueEnd);171if (!Ok)172InvokeIfNonNull(173Printf, "GWP-ASan: Invalid integer value '%s' for option '%s'.\n",174Value, Options[I].Name);175break;176}177return Ok;178}179180InvokeIfNonNull(Printf, "GWP-ASan: Unknown option '%s'.", Name);181return true;182}183184void OptionParser::registerOption(const char *Name, const char *Desc,185OptionType Type, void *Var) {186assert(NumberOfOptions < MaxOptions &&187"GWP-ASan Error: Ran out of space for options.\n");188Options[NumberOfOptions].Name = Name;189Options[NumberOfOptions].Desc = Desc;190Options[NumberOfOptions].Type = Type;191Options[NumberOfOptions].Var = Var;192++NumberOfOptions;193}194195void registerGwpAsanOptions(OptionParser *parser,196gwp_asan::options::Options *o) {197#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \198parser->registerOption(#Name, Description, OptionType::OT_##Type, &o->Name);199#include "gwp_asan/options.inc"200#undef GWP_ASAN_OPTION201}202203const char *getGwpAsanDefaultOptions() {204return (__gwp_asan_default_options) ? __gwp_asan_default_options() : "";205}206207gwp_asan::options::Options *getOptionsInternal() {208static gwp_asan::options::Options GwpAsanOptions;209return &GwpAsanOptions;210}211} // anonymous namespace212213namespace gwp_asan {214namespace options {215216void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings) {217Options *o = getOptionsInternal();218o->setDefaults();219220OptionParser Parser(PrintfForWarnings);221registerGwpAsanOptions(&Parser, o);222223// Override from the weak function definition in this executable.224Parser.parseString(getGwpAsanDefaultOptions());225226// Override from the provided options string.227Parser.parseString(OptionsStr);228229if (o->help)230Parser.printOptionDescriptions();231232if (!o->Enabled)233return;234235if (o->MaxSimultaneousAllocations <= 0) {236InvokeIfNonNull(237PrintfForWarnings,238"GWP-ASan ERROR: MaxSimultaneousAllocations must be > 0 when GWP-ASan "239"is enabled.\n");240o->Enabled = false;241}242if (o->SampleRate <= 0) {243InvokeIfNonNull(244PrintfForWarnings,245"GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n");246o->Enabled = false;247}248}249250void initOptions(Printf_t PrintfForWarnings) {251initOptions(getenv("GWP_ASAN_OPTIONS"), PrintfForWarnings);252}253254Options &getOptions() { return *getOptionsInternal(); }255256} // namespace options257} // namespace gwp_asan258259260