[GWP-ASan] Add inbuilt options parser.

Adds a modified options parser (shamefully pulled from Scudo, which
shamefully pulled it from sanitizer-common) to GWP-ASan. This allows
customers (Android) to parse options strings in a common way.

Depends on D94117.

AOSP side of these patches is staged at:

 - sepolicy (sysprops should only be settable by the shell, in both root and
 unrooted conditions):
 https://android-review.googlesource.com/c/platform/system/sepolicy/+/1517238

 - zygote updates:
 https://android-review.googlesource.com/c/platform/frameworks/base/+/1515009

 - bionic changes to add `gwp_asan.<process_name>` system property, and
 GWP_ASAN_OPTIONS environment variable:
 https://android-review.googlesource.com/c/platform/bionic/+/1514989

Reviewed By: eugenis

Differential Revision: https://reviews.llvm.org/D92696
This commit is contained in:
Mitch Phillips 2021-01-15 12:57:00 -08:00
parent a14c36fe27
commit 6a42cbf6d2
15 changed files with 334 additions and 105 deletions

View File

@ -41,11 +41,10 @@ append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC GWP_ASAN_CFLAGS)
# Remove -stdlib= which is unused when passing -nostdinc++.
string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# Options parsing support is optional. GwpAsan is totally independent of
# sanitizer_common, the options parser is not. This is an optional library
# that can be used by an allocator to automatically parse GwpAsan options from
# the environment variable GWP_ASAN_FLAGS, but the allocator can choose to
# implement its own options parsing and populate the Options struct itself.
# Options parsing support is optional. This is an optional library that can be
# used by an allocator to automatically parse GwpAsan options from the
# environment variable GWP_ASAN_FLAGS, but the allocator can choose to implement
# its own options parsing and populate the Options struct itself.
set(GWP_ASAN_OPTIONS_PARSER_SOURCES
optional/options_parser.cpp
)
@ -64,11 +63,7 @@ set(GWP_ASAN_SEGV_HANDLER_HEADERS
options.h)
set(GWP_ASAN_OPTIONS_PARSER_CFLAGS
${GWP_ASAN_CFLAGS}
${SANITIZER_COMMON_CFLAGS})
set(GWP_ASAN_OPTIONS_PARSER_OBJECT_LIBS
RTSanitizerCommon
RTSanitizerCommonNoLibc)
${GWP_ASAN_CFLAGS})
if (COMPILER_RT_HAS_GWP_ASAN)
foreach(arch ${GWP_ASAN_SUPPORTED_ARCH})
@ -89,11 +84,6 @@ if (COMPILER_RT_HAS_GWP_ASAN)
ADDITIONAL_HEADERS ${GWP_ASAN_HEADERS}
CFLAGS ${GWP_ASAN_CFLAGS})
# Note: If you choose to add this as an object library, ensure you also
# include the sanitizer_common flag parsing object lib (generally
# 'RTSanitizerCommonNoTermination'). Also, you'll need to either implement
# your own backtrace support (see optional/backtrace.h), or choose between one
# of the pre-implemented backtrace support options (see below).
add_compiler_rt_object_libraries(RTGwpAsanOptionsParser
ARCHS ${GWP_ASAN_SUPPORTED_ARCH}
SOURCES ${GWP_ASAN_OPTIONS_PARSER_SOURCES}

View File

@ -7,84 +7,251 @@
//===----------------------------------------------------------------------===//
#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>
#include "gwp_asan/options.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "sanitizer_common/sanitizer_flags.h"
namespace gwp_asan {
namespace options {
namespace {
void registerGwpAsanFlags(__sanitizer::FlagParser *parser, Options *o) {
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
RegisterFlag(parser, #Name, Description, &o->Name);
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);
}
const char *getCompileDefinitionGwpAsanDefaultOptions() {
#ifdef GWP_ASAN_DEFAULT_OPTIONS
return SANITIZER_STRINGIFY(GWP_ASAN_DEFAULT_OPTIONS);
#else
return "";
#endif
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() : "";
}
Options *getOptionsInternal() {
static Options GwpAsanFlags;
return &GwpAsanFlags;
gwp_asan::options::Options *getOptionsInternal() {
static gwp_asan::options::Options GwpAsanOptions;
return &GwpAsanOptions;
}
} // anonymous namespace
void initOptions() {
__sanitizer::SetCommonFlagsDefaults();
namespace gwp_asan {
namespace options {
void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings) {
Options *o = getOptionsInternal();
o->setDefaults();
__sanitizer::FlagParser Parser;
registerGwpAsanFlags(&Parser, o);
OptionParser Parser(PrintfForWarnings);
registerGwpAsanOptions(&Parser, o);
// Override from compile definition.
Parser.ParseString(getCompileDefinitionGwpAsanDefaultOptions());
// Override from the weak function definition in this executable.
Parser.parseString(getGwpAsanDefaultOptions());
// Override from user-specified string.
Parser.ParseString(getGwpAsanDefaultOptions());
// Override from the provided options string.
Parser.parseString(OptionsStr);
// Override from environment.
Parser.ParseString(__sanitizer::GetEnv("GWP_ASAN_OPTIONS"));
__sanitizer::InitializeCommonFlags();
if (__sanitizer::Verbosity())
__sanitizer::ReportUnrecognizedFlags();
if (o->help)
Parser.printOptionDescriptions();
if (!o->Enabled)
return;
// Sanity checks for the parameters.
if (o->MaxSimultaneousAllocations <= 0) {
__sanitizer::Printf("GWP-ASan ERROR: MaxSimultaneousAllocations must be > "
"0 when GWP-ASan is enabled.\n");
exit(EXIT_FAILURE);
InvokeIfNonNull(
PrintfForWarnings,
"GWP-ASan ERROR: MaxSimultaneousAllocations must be > 0 when GWP-ASan "
"is enabled.\n");
o->Enabled = false;
}
if (o->SampleRate < 1) {
__sanitizer::Printf(
if (o->SampleRate <= 0) {
InvokeIfNonNull(
PrintfForWarnings,
"GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n");
exit(EXIT_FAILURE);
o->Enabled = false;
}
}
void initOptions(Printf_t PrintfForWarnings) {
initOptions(getenv("GWP_ASAN_OPTIONS"), PrintfForWarnings);
}
Options &getOptions() { return *getOptionsInternal(); }
} // namespace options

View File

@ -9,14 +9,15 @@
#ifndef GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
#define GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
#include "gwp_asan/optional/backtrace.h"
#include "gwp_asan/optional/printf.h"
#include "gwp_asan/options.h"
#include "sanitizer_common/sanitizer_common.h"
namespace gwp_asan {
namespace options {
// Parse the options from the GWP_ASAN_FLAGS environment variable.
void initOptions();
// Parse the options from the GWP_ASAN_OPTIONS environment variable.
void initOptions(Printf_t PrintfForWarnings = nullptr);
// Parse the options from the provided string.
void initOptions(const char *OptionsStr, Printf_t PrintfForWarnings = nullptr);
// Returns the initialised options. Call initOptions() prior to calling this
// function.
Options &getOptions();
@ -24,8 +25,7 @@ Options &getOptions();
} // namespace gwp_asan
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *
__gwp_asan_default_options();
__attribute__((weak)) const char *__gwp_asan_default_options();
}
#endif // GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_

View File

@ -62,3 +62,18 @@ GWP_ASAN_OPTION(
GWP_ASAN_OPTION(bool, InstallForkHandlers, true,
"Install GWP-ASan atfork handlers to acquire internal locks "
"before fork and release them after.")
GWP_ASAN_OPTION(bool, help, false, "Print a summary of the available options.")
// =============================================================================
// ==== WARNING
// =============================================================================
// If you are adding flags to GWP-ASan, please note that GWP-ASan flag strings
// may be parsed by trusted system components (on Android, GWP-ASan flag strings
// are parsed by libc during the dynamic loader). This means that GWP-ASan
// should never feature flags like log paths on disk, because this can lead to
// arbitrary file write and thus privilege escalation. For an example, see the
// setuid ASan log_path exploits: https://www.exploit-db.com/exploits/46241.
//
// Please place all new flags above this warning, so that the warning always
// stays at the bottom.

View File

@ -23,7 +23,8 @@ set(GWP_ASAN_UNITTESTS
thread_contention.cpp
harness.cpp
enable_disable.cpp
late_init.cpp)
late_init.cpp
options.cpp)
set(GWP_ASAN_UNIT_TEST_HEADERS
${GWP_ASAN_HEADERS}
@ -48,6 +49,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST GWP_ASAN_SUPPORTED_ARCH)
$<TARGET_OBJECTS:RTGwpAsan.${arch}>
$<TARGET_OBJECTS:RTGwpAsanBacktraceSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTGwpAsanSegvHandler.${arch}>
$<TARGET_OBJECTS:RTGwpAsanOptionsParser.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>)

View File

@ -0,0 +1,63 @@
//===-- options.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/tests/harness.h"
#include "gwp_asan/optional/options_parser.h"
#include "gwp_asan/options.h"
#include <stdarg.h>
static char Message[1024];
void MessageRecorder(const char *Format, ...) {
va_list Args;
va_start(Args, Format);
vsprintf(Message + strlen(Message), Format, Args);
va_end(Args);
}
TEST(GwpAsanOptionsTest, Basic) {
Message[0] = '\0';
gwp_asan::options::initOptions("Enabled=0:SampleRate=4:"
"InstallSignalHandlers=false",
MessageRecorder);
gwp_asan::options::Options Opts = gwp_asan::options::getOptions();
EXPECT_EQ('\0', Message[0]);
EXPECT_FALSE(Opts.Enabled);
EXPECT_FALSE(Opts.InstallSignalHandlers);
EXPECT_EQ(4, Opts.SampleRate);
}
void RunErrorTest(const char *OptionsStr, const char *ErrorNeedle) {
Message[0] = '\0';
gwp_asan::options::initOptions(OptionsStr, MessageRecorder);
EXPECT_NE('\0', Message[0])
<< "Options string \"" << OptionsStr << "\" didn't generate an error.";
EXPECT_NE(nullptr, strstr(Message, ErrorNeedle))
<< "Couldn't find error needle \"" << ErrorNeedle
<< "\" in haystack created by options string \"" << OptionsStr
<< "\". Error was: \"" << Message << "\".";
}
TEST(GwpAsanOptionsTest, FailureModes) {
RunErrorTest("Enabled=2", "Invalid boolean value '2' for option 'Enabled'");
RunErrorTest("Enabled=1:MaxSimultaneousAllocations=0",
"MaxSimultaneousAllocations must be > 0");
RunErrorTest("Enabled=1:MaxSimultaneousAllocations=-1",
"MaxSimultaneousAllocations must be > 0");
RunErrorTest("Enabled=1:SampleRate=0", "SampleRate must be > 0");
RunErrorTest("Enabled=1:SampleRate=-1", "SampleRate must be > 0");
RunErrorTest("Enabled=", "Invalid boolean value '' for option 'Enabled'");
RunErrorTest("==", "Unknown option '=='");
RunErrorTest("Enabled==0", "Invalid boolean value '=0' for option 'Enabled'");
RunErrorTest("Enabled:", "Expected '=' when parsing option 'Enabled:'");
RunErrorTest("Enabled:=", "Expected '=' when parsing option 'Enabled:='");
RunErrorTest("SampleRate=NOT_A_NUMBER",
"Invalid integer value 'NOT_A_NUMBER' for option 'SampleRate'");
RunErrorTest("NOT_A_VALUE=0", "Unknown option 'NOT_A_VALUE");
}

View File

@ -672,7 +672,8 @@ static BackendT &getBackend() {
void initScudo() {
Instance.init();
#ifdef GWP_ASAN_HOOKS
gwp_asan::options::initOptions();
gwp_asan::options::initOptions(__sanitizer::GetEnv("GWP_ASAN_OPTIONS"),
Printf);
gwp_asan::options::Options &Opts = gwp_asan::options::getOptions();
Opts.Backtrace = gwp_asan::backtrace::getBacktraceFunction();
GuardedAlloc.init(Opts);

View File

@ -120,7 +120,7 @@ set(SCUDO_OBJECT_LIBS)
if (COMPILER_RT_HAS_GWP_ASAN)
list(APPEND SCUDO_OBJECT_LIBS
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler)
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler RTGwpAsanOptionsParser)
list(APPEND SCUDO_CFLAGS -DGWP_ASAN_HOOKS)
endif()

View File

@ -28,6 +28,7 @@
#ifdef GWP_ASAN_HOOKS
#include "gwp_asan/guarded_pool_allocator.h"
#include "gwp_asan/optional/backtrace.h"
#include "gwp_asan/optional/options_parser.h"
#include "gwp_asan/optional/segv_handler.h"
#endif // GWP_ASAN_HOOKS
@ -183,17 +184,12 @@ public:
// be functional, best called from PostInitCallback.
void initGwpAsan() {
#ifdef GWP_ASAN_HOOKS
gwp_asan::options::Options Opt;
Opt.Enabled = getFlags()->GWP_ASAN_Enabled;
// Bear in mind - Scudo has its own alignment guarantees that are strictly
// enforced. Scudo exposes the same allocation function for everything from
// malloc() to posix_memalign, so in general this flag goes unused, as Scudo
// will always ask GWP-ASan for an aligned amount of bytes.
Opt.PerfectlyRightAlign = getFlags()->GWP_ASAN_PerfectlyRightAlign;
Opt.MaxSimultaneousAllocations =
getFlags()->GWP_ASAN_MaxSimultaneousAllocations;
Opt.SampleRate = getFlags()->GWP_ASAN_SampleRate;
Opt.InstallSignalHandlers = getFlags()->GWP_ASAN_InstallSignalHandlers;
gwp_asan::options::initOptions(getEnv("GWP_ASAN_OPTIONS"), Printf);
gwp_asan::options::Options Opt = gwp_asan::options::getOptions();
// Embedded GWP-ASan is locked through the Scudo atfork handler (via
// Allocator::disable calling GWPASan.disable). Disable GWP-ASan's atfork
// handler.

View File

@ -23,13 +23,6 @@ void Flags::setDefaults() {
#define SCUDO_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "flags.inc"
#undef SCUDO_FLAG
#ifdef GWP_ASAN_HOOKS
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
GWP_ASAN_##Name = DefaultValue;
#include "gwp_asan/options.inc"
#undef GWP_ASAN_OPTION
#endif // GWP_ASAN_HOOKS
}
void registerFlags(FlagParser *Parser, Flags *F) {
@ -38,14 +31,6 @@ void registerFlags(FlagParser *Parser, Flags *F) {
reinterpret_cast<void *>(&F->Name));
#include "flags.inc"
#undef SCUDO_FLAG
#ifdef GWP_ASAN_HOOKS
#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
Parser->registerFlag("GWP_ASAN_" #Name, Description, FlagType::FT_##Type, \
reinterpret_cast<void *>(&F->GWP_ASAN_##Name));
#include "gwp_asan/options.inc"
#undef GWP_ASAN_OPTION
#endif // GWP_ASAN_HOOKS
}
static const char *getCompileDefinitionScudoDefaultOptions() {

View File

@ -45,7 +45,7 @@ macro(add_scudo_unittest testname)
cmake_parse_arguments(TEST "" "" "SOURCES;ADDITIONAL_RTOBJECTS" ${ARGN})
if (COMPILER_RT_HAS_GWP_ASAN)
list(APPEND TEST_ADDITIONAL_RTOBJECTS
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler)
RTGwpAsan RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler RTGwpAsanOptionsParser)
endif()
if(COMPILER_RT_HAS_SCUDO_STANDALONE)

View File

@ -117,18 +117,3 @@ TEST(ScudoFlagsTest, AllocatorFlags) {
EXPECT_TRUE(Flags.delete_size_mismatch);
EXPECT_EQ(2048, Flags.quarantine_max_chunk_size);
}
#ifdef GWP_ASAN_HOOKS
TEST(ScudoFlagsTest, GWPASanFlags) {
scudo::FlagParser Parser;
scudo::Flags Flags;
scudo::registerFlags(&Parser, &Flags);
Flags.setDefaults();
Flags.GWP_ASAN_Enabled = false;
Parser.parseString("GWP_ASAN_Enabled=true:GWP_ASAN_SampleRate=1:"
"GWP_ASAN_InstallSignalHandlers=false");
EXPECT_TRUE(Flags.GWP_ASAN_Enabled);
EXPECT_FALSE(Flags.GWP_ASAN_InstallSignalHandlers);
EXPECT_EQ(1, Flags.GWP_ASAN_SampleRate);
}
#endif // GWP_ASAN_HOOKS

View File

@ -13,4 +13,4 @@ config.test_source_root = config.test_exec_root
# Disable GWP-ASan for scudo internal tests.
if config.gwp_asan:
config.environment['SCUDO_OPTIONS'] = 'GWP_ASAN_Enabled=0'
config.environment['GWP_ASAN_OPTIONS'] = 'Enabled=false'

View File

@ -14,7 +14,20 @@ if (LLVM_USE_SANITIZE_COVERAGE)
target_include_directories(
stack_trace_compressor_fuzzer PRIVATE ../../lib/)
add_executable(options_parser_fuzzer
../../lib/gwp_asan/optional/options_parser.cpp
../../lib/gwp_asan/optional/options_parser.h
options_parser_fuzzer.cpp)
set_target_properties(
options_parser_fuzzer PROPERTIES FOLDER "Fuzzers")
target_compile_options(
options_parser_fuzzer PRIVATE -fsanitize=fuzzer-no-link)
set_target_properties(
options_parser_fuzzer PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
target_include_directories(
options_parser_fuzzer PRIVATE ../../lib/)
if (TARGET gwp_asan)
add_dependencies(gwp_asan stack_trace_compressor_fuzzer)
add_dependencies(gwp_asan stack_trace_compressor_fuzzer options_parser_fuzzer)
endif()
endif()

View File

@ -0,0 +1,12 @@
#include <cstddef>
#include <cstdint>
#include <fuzzer/FuzzedDataProvider.h>
#include "gwp_asan/optional/options_parser.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzedDataProvider Fdp(Data, Size);
gwp_asan::options::initOptions(Fdp.ConsumeRemainingBytesAsString().c_str());
return 0;
}