Path: blob/main/contrib/llvm-project/compiler-rt/lib/scudo/standalone/flags_parser.cpp
35291 views
//===-- flags_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 "flags_parser.h"9#include "common.h"10#include "report.h"1112#include <errno.h>13#include <limits.h>14#include <stdlib.h>15#include <string.h>1617namespace scudo {1819class UnknownFlagsRegistry {20static const u32 MaxUnknownFlags = 16;21const char *UnknownFlagsNames[MaxUnknownFlags];22u32 NumberOfUnknownFlags;2324public:25void add(const char *Name) {26CHECK_LT(NumberOfUnknownFlags, MaxUnknownFlags);27UnknownFlagsNames[NumberOfUnknownFlags++] = Name;28}2930void report() {31if (!NumberOfUnknownFlags)32return;33Printf("Scudo WARNING: found %d unrecognized flag(s):\n",34NumberOfUnknownFlags);35for (u32 I = 0; I < NumberOfUnknownFlags; ++I)36Printf(" %s\n", UnknownFlagsNames[I]);37NumberOfUnknownFlags = 0;38}39};40static UnknownFlagsRegistry UnknownFlags;4142void reportUnrecognizedFlags() { UnknownFlags.report(); }4344void FlagParser::printFlagDescriptions() {45Printf("Available flags for Scudo:\n");46for (u32 I = 0; I < NumberOfFlags; ++I)47Printf("\t%s\n\t\t- %s\n", Flags[I].Name, Flags[I].Desc);48}4950static bool isSeparator(char C) {51return C == ' ' || C == ',' || C == ':' || C == '\n' || C == '\t' ||52C == '\r';53}5455static bool isSeparatorOrNull(char C) { return !C || isSeparator(C); }5657void FlagParser::skipWhitespace() {58while (isSeparator(Buffer[Pos]))59++Pos;60}6162void FlagParser::parseFlag() {63const uptr NameStart = Pos;64while (Buffer[Pos] != '=' && !isSeparatorOrNull(Buffer[Pos]))65++Pos;66if (Buffer[Pos] != '=')67reportError("expected '='");68const char *Name = Buffer + NameStart;69const uptr ValueStart = ++Pos;70const char *Value;71if (Buffer[Pos] == '\'' || Buffer[Pos] == '"') {72const char Quote = Buffer[Pos++];73while (Buffer[Pos] != 0 && Buffer[Pos] != Quote)74++Pos;75if (Buffer[Pos] == 0)76reportError("unterminated string");77Value = Buffer + ValueStart + 1;78++Pos; // consume the closing quote79} else {80while (!isSeparatorOrNull(Buffer[Pos]))81++Pos;82Value = Buffer + ValueStart;83}84if (!runHandler(Name, Value, '='))85reportError("flag parsing failed.");86}8788void FlagParser::parseFlags() {89while (true) {90skipWhitespace();91if (Buffer[Pos] == 0)92break;93parseFlag();94}95}9697void FlagParser::parseString(const char *S) {98if (!S)99return;100// Backup current parser state to allow nested parseString() calls.101const char *OldBuffer = Buffer;102const uptr OldPos = Pos;103Buffer = S;104Pos = 0;105106parseFlags();107108Buffer = OldBuffer;109Pos = OldPos;110}111112inline bool parseBool(const char *Value, bool *b) {113if (strncmp(Value, "0", 1) == 0 || strncmp(Value, "no", 2) == 0 ||114strncmp(Value, "false", 5) == 0) {115*b = false;116return true;117}118if (strncmp(Value, "1", 1) == 0 || strncmp(Value, "yes", 3) == 0 ||119strncmp(Value, "true", 4) == 0) {120*b = true;121return true;122}123return false;124}125126void FlagParser::parseStringPair(const char *Name, const char *Value) {127if (!runHandler(Name, Value, '\0'))128reportError("flag parsing failed.");129}130131bool FlagParser::runHandler(const char *Name, const char *Value,132const char Sep) {133for (u32 I = 0; I < NumberOfFlags; ++I) {134const uptr Len = strlen(Flags[I].Name);135if (strncmp(Name, Flags[I].Name, Len) != 0 || Name[Len] != Sep)136continue;137bool Ok = false;138switch (Flags[I].Type) {139case FlagType::FT_bool:140Ok = parseBool(Value, reinterpret_cast<bool *>(Flags[I].Var));141if (!Ok)142reportInvalidFlag("bool", Value);143break;144case FlagType::FT_int:145char *ValueEnd;146errno = 0;147long V = strtol(Value, &ValueEnd, 10);148if (errno != 0 || // strtol failed (over or underflow)149V > INT_MAX || V < INT_MIN || // overflows integer150// contains unexpected characters151(*ValueEnd != '"' && *ValueEnd != '\'' &&152!isSeparatorOrNull(*ValueEnd))) {153reportInvalidFlag("int", Value);154break;155}156*reinterpret_cast<int *>(Flags[I].Var) = static_cast<int>(V);157Ok = true;158break;159}160return Ok;161}162// Unrecognized flag. This is not a fatal error, we may print a warning later.163UnknownFlags.add(Name);164return true;165}166167void FlagParser::registerFlag(const char *Name, const char *Desc, FlagType Type,168void *Var) {169CHECK_LT(NumberOfFlags, MaxFlags);170Flags[NumberOfFlags].Name = Name;171Flags[NumberOfFlags].Desc = Desc;172Flags[NumberOfFlags].Type = Type;173Flags[NumberOfFlags].Var = Var;174++NumberOfFlags;175}176177} // namespace scudo178179180