2015-01-15 23:13:43 +08:00
|
|
|
//===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2015-01-15 23:13:43 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef SANITIZER_FLAG_REGISTRY_H
|
|
|
|
#define SANITIZER_FLAG_REGISTRY_H
|
|
|
|
|
|
|
|
#include "sanitizer_internal_defs.h"
|
|
|
|
#include "sanitizer_libc.h"
|
|
|
|
#include "sanitizer_common.h"
|
|
|
|
|
|
|
|
namespace __sanitizer {
|
|
|
|
|
|
|
|
class FlagHandlerBase {
|
|
|
|
public:
|
|
|
|
virtual bool Parse(const char *value) { return false; }
|
2019-10-29 08:53:38 +08:00
|
|
|
// Write the C string representation of the current value (truncated to fit)
|
|
|
|
// into the buffer of size `size`. Returns false if truncation occurred and
|
|
|
|
// returns true otherwise.
|
|
|
|
virtual bool Format(char *buffer, uptr size) {
|
|
|
|
if (size > 0)
|
|
|
|
buffer[0] = '\0';
|
|
|
|
return false;
|
|
|
|
}
|
2019-04-25 03:01:04 +08:00
|
|
|
|
|
|
|
protected:
|
2019-09-12 10:20:36 +08:00
|
|
|
~FlagHandlerBase() {}
|
2019-10-29 08:53:38 +08:00
|
|
|
|
|
|
|
inline bool FormatString(char *buffer, uptr size, const char *str_to_use) {
|
|
|
|
uptr num_symbols_should_write =
|
|
|
|
internal_snprintf(buffer, size, "%s", str_to_use);
|
|
|
|
return num_symbols_should_write < size;
|
|
|
|
}
|
2015-01-15 23:13:43 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
2020-11-03 09:33:22 +08:00
|
|
|
class FlagHandler final : public FlagHandlerBase {
|
2015-01-15 23:13:43 +08:00
|
|
|
T *t_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit FlagHandler(T *t) : t_(t) {}
|
2015-02-12 08:36:39 +08:00
|
|
|
bool Parse(const char *value) final;
|
2019-10-29 08:53:38 +08:00
|
|
|
bool Format(char *buffer, uptr size) final;
|
2015-01-15 23:13:43 +08:00
|
|
|
};
|
|
|
|
|
2017-05-20 06:37:16 +08:00
|
|
|
inline bool ParseBool(const char *value, bool *b) {
|
2015-01-15 23:13:43 +08:00
|
|
|
if (internal_strcmp(value, "0") == 0 ||
|
|
|
|
internal_strcmp(value, "no") == 0 ||
|
|
|
|
internal_strcmp(value, "false") == 0) {
|
2017-05-20 06:37:16 +08:00
|
|
|
*b = false;
|
2015-01-15 23:13:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (internal_strcmp(value, "1") == 0 ||
|
|
|
|
internal_strcmp(value, "yes") == 0 ||
|
|
|
|
internal_strcmp(value, "true") == 0) {
|
2017-05-20 06:37:16 +08:00
|
|
|
*b = true;
|
2015-01-15 23:13:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
2017-05-20 06:37:16 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<bool>::Parse(const char *value) {
|
|
|
|
if (ParseBool(value, t_)) return true;
|
2015-01-15 23:13:43 +08:00
|
|
|
Printf("ERROR: Invalid value for bool option: '%s'\n", value);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-29 08:53:38 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
|
|
|
|
return FormatString(buffer, size, *t_ ? "true" : "false");
|
|
|
|
}
|
|
|
|
|
2017-05-20 06:37:16 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
|
|
|
|
bool b;
|
|
|
|
if (ParseBool(value, &b)) {
|
|
|
|
*t_ = b ? kHandleSignalYes : kHandleSignalNo;
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-26 07:42:33 +08:00
|
|
|
if (internal_strcmp(value, "2") == 0 ||
|
|
|
|
internal_strcmp(value, "exclusive") == 0) {
|
|
|
|
*t_ = kHandleSignalExclusive;
|
|
|
|
return true;
|
|
|
|
}
|
2017-05-20 06:37:16 +08:00
|
|
|
Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-29 08:53:38 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) {
|
|
|
|
uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
|
|
|
|
return num_symbols_should_write < size;
|
|
|
|
}
|
|
|
|
|
2015-01-15 23:13:43 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<const char *>::Parse(const char *value) {
|
[sanitizer] Do not over-dup string flags
Summary:
String flags values appear to be duped twice. Once in `FlagParser::parse_flag`
using the `LowLevelAllocator` via `ll_strndup`, once in
`FlagHandler<const char *>::Parse` using the `InternalAllocator` via
`internal_strdup`. It looks like the second one is redundant, as the memory
for the first one is never freed and not used for anything else.
Assigning the value to the flag instead of duping it has a few advantages:
- if it was the only use of the `InternalAllocator` (which is the case for
Scudo), then the related code will not be compiled it, which saves us a
whole instantiation of the CombinedAllocator worth of extra code;
- in the event a string flag is parsed, the `InternalAllocator` would have
created a whole SizeClassAllocator32 region for a single allocation, which is
kind of wasteful.
- also, the string is dup'ed twice for the whole lifetime of a process.
I tested check-{sanitizer,asan,tsan,ubsan,scudo} successfully, so as far as I
can tell this doesn't appear to have bad side effects.
Reviewers: eugenis, alekseyshl
Reviewed By: eugenis
Subscribers: kubamracek, llvm-commits
Differential Revision: https://reviews.llvm.org/D36970
llvm-svn: 311386
2017-08-22 05:25:38 +08:00
|
|
|
*t_ = value;
|
2015-01-15 23:13:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-29 08:53:38 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
|
|
|
|
return FormatString(buffer, size, *t_);
|
|
|
|
}
|
|
|
|
|
2015-01-15 23:13:43 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<int>::Parse(const char *value) {
|
2018-06-17 16:41:45 +08:00
|
|
|
const char *value_end;
|
2015-01-15 23:13:43 +08:00
|
|
|
*t_ = internal_simple_strtoll(value, &value_end, 10);
|
|
|
|
bool ok = *value_end == 0;
|
|
|
|
if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2019-10-29 08:53:38 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<int>::Format(char *buffer, uptr size) {
|
|
|
|
uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
|
|
|
|
return num_symbols_should_write < size;
|
|
|
|
}
|
|
|
|
|
2015-01-15 23:13:43 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<uptr>::Parse(const char *value) {
|
2018-06-17 16:41:45 +08:00
|
|
|
const char *value_end;
|
2015-01-15 23:13:43 +08:00
|
|
|
*t_ = internal_simple_strtoll(value, &value_end, 10);
|
|
|
|
bool ok = *value_end == 0;
|
|
|
|
if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2019-10-29 08:53:38 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
|
2021-08-13 01:47:23 +08:00
|
|
|
uptr num_symbols_should_write = internal_snprintf(buffer, size, "0x%zx", *t_);
|
2019-10-29 08:53:38 +08:00
|
|
|
return num_symbols_should_write < size;
|
|
|
|
}
|
|
|
|
|
2019-05-01 07:07:10 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<s64>::Parse(const char *value) {
|
|
|
|
const char *value_end;
|
|
|
|
*t_ = internal_simple_strtoll(value, &value_end, 10);
|
|
|
|
bool ok = *value_end == 0;
|
|
|
|
if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2019-10-29 08:53:38 +08:00
|
|
|
template <>
|
|
|
|
inline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
|
|
|
|
uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_);
|
|
|
|
return num_symbols_should_write < size;
|
|
|
|
}
|
|
|
|
|
2015-01-15 23:13:43 +08:00
|
|
|
class FlagParser {
|
|
|
|
static const int kMaxFlags = 200;
|
|
|
|
struct Flag {
|
|
|
|
const char *name;
|
|
|
|
const char *desc;
|
|
|
|
FlagHandlerBase *handler;
|
|
|
|
} *flags_;
|
|
|
|
int n_flags_;
|
|
|
|
|
|
|
|
const char *buf_;
|
|
|
|
uptr pos_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
FlagParser();
|
|
|
|
void RegisterHandler(const char *name, FlagHandlerBase *handler,
|
|
|
|
const char *desc);
|
2019-06-15 09:37:14 +08:00
|
|
|
void ParseString(const char *s, const char *env_name = 0);
|
|
|
|
void ParseStringFromEnv(const char *env_name);
|
2015-07-22 07:03:13 +08:00
|
|
|
bool ParseFile(const char *path, bool ignore_missing);
|
2015-01-15 23:13:43 +08:00
|
|
|
void PrintFlagDescriptions();
|
|
|
|
|
2015-01-19 19:47:13 +08:00
|
|
|
static LowLevelAllocator Alloc;
|
|
|
|
|
2015-01-15 23:13:43 +08:00
|
|
|
private:
|
|
|
|
void fatal_error(const char *err);
|
|
|
|
bool is_space(char c);
|
|
|
|
void skip_whitespace();
|
2019-06-15 09:37:14 +08:00
|
|
|
void parse_flags(const char *env_option_name);
|
|
|
|
void parse_flag(const char *env_option_name);
|
2015-01-15 23:13:43 +08:00
|
|
|
bool run_handler(const char *name, const char *value);
|
2015-01-19 19:47:13 +08:00
|
|
|
char *ll_strndup(const char *s, uptr n);
|
2015-01-15 23:13:43 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
|
|
|
|
T *var) {
|
2019-09-12 07:19:48 +08:00
|
|
|
FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var);
|
2015-01-15 23:13:43 +08:00
|
|
|
parser->RegisterHandler(name, fh, desc);
|
|
|
|
}
|
|
|
|
|
2015-01-19 20:22:57 +08:00
|
|
|
void ReportUnrecognizedFlags();
|
|
|
|
|
2015-01-15 23:13:43 +08:00
|
|
|
} // namespace __sanitizer
|
|
|
|
|
|
|
|
#endif // SANITIZER_FLAG_REGISTRY_H
|