[llvm-branch-commits] [compiler-rt] 6a42cbf - [GWP-ASan] Add inbuilt options parser.
Mitch Phillips via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jan 15 13:22:28 PST 2021
Author: Mitch Phillips
Date: 2021-01-15T12:57:05-08:00
New Revision: 6a42cbf6d2116b52cb59aa3e23bef93a30cf2dc8
URL: https://github.com/llvm/llvm-project/commit/6a42cbf6d2116b52cb59aa3e23bef93a30cf2dc8
DIFF: https://github.com/llvm/llvm-project/commit/6a42cbf6d2116b52cb59aa3e23bef93a30cf2dc8.diff
LOG: [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
Added:
compiler-rt/lib/gwp_asan/tests/options.cpp
compiler-rt/tools/gwp_asan/options_parser_fuzzer.cpp
Modified:
compiler-rt/lib/gwp_asan/CMakeLists.txt
compiler-rt/lib/gwp_asan/optional/options_parser.cpp
compiler-rt/lib/gwp_asan/optional/options_parser.h
compiler-rt/lib/gwp_asan/options.inc
compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
compiler-rt/lib/scudo/scudo_allocator.cpp
compiler-rt/lib/scudo/standalone/CMakeLists.txt
compiler-rt/lib/scudo/standalone/combined.h
compiler-rt/lib/scudo/standalone/flags.cpp
compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
compiler-rt/test/scudo/standalone/unit/lit.site.cfg.py.in
compiler-rt/tools/gwp_asan/CMakeLists.txt
Removed:
################################################################################
diff --git a/compiler-rt/lib/gwp_asan/CMakeLists.txt b/compiler-rt/lib/gwp_asan/CMakeLists.txt
index 92f578585b54..599fa9904e47 100644
--- a/compiler-rt/lib/gwp_asan/CMakeLists.txt
+++ b/compiler-rt/lib/gwp_asan/CMakeLists.txt
@@ -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}
diff --git a/compiler-rt/lib/gwp_asan/optional/options_parser.cpp b/compiler-rt/lib/gwp_asan/optional/options_parser.cpp
index 2e6386286745..60234124e8ed 100644
--- a/compiler-rt/lib/gwp_asan/optional/options_parser.cpp
+++ b/compiler-rt/lib/gwp_asan/optional/options_parser.cpp
@@ -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);
+}
+
+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);
}
-const char *getCompileDefinitionGwpAsanDefaultOptions() {
-#ifdef GWP_ASAN_DEFAULT_OPTIONS
- return SANITIZER_STRINGIFY(GWP_ASAN_DEFAULT_OPTIONS);
-#else
- return "";
-#endif
+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);
-
- // Override from compile definition.
- Parser.ParseString(getCompileDefinitionGwpAsanDefaultOptions());
+ OptionParser Parser(PrintfForWarnings);
+ registerGwpAsanOptions(&Parser, o);
- // Override from user-specified string.
- Parser.ParseString(getGwpAsanDefaultOptions());
+ // Override from the weak function definition in this executable.
+ Parser.parseString(getGwpAsanDefaultOptions());
- // Override from environment.
- Parser.ParseString(__sanitizer::GetEnv("GWP_ASAN_OPTIONS"));
+ // Override from the provided options string.
+ Parser.parseString(OptionsStr);
- __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
diff --git a/compiler-rt/lib/gwp_asan/optional/options_parser.h b/compiler-rt/lib/gwp_asan/optional/options_parser.h
index 7a6bfaf0ce3e..a5a062801f8f 100644
--- a/compiler-rt/lib/gwp_asan/optional/options_parser.h
+++ b/compiler-rt/lib/gwp_asan/optional/options_parser.h
@@ -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_
diff --git a/compiler-rt/lib/gwp_asan/options.inc b/compiler-rt/lib/gwp_asan/options.inc
index 67dcfae170a8..4834daef6003 100644
--- a/compiler-rt/lib/gwp_asan/options.inc
+++ b/compiler-rt/lib/gwp_asan/options.inc
@@ -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.
diff --git a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
index c9634e471d99..abc02a49637c 100644
--- a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
@@ -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}>)
diff --git a/compiler-rt/lib/gwp_asan/tests/options.cpp b/compiler-rt/lib/gwp_asan/tests/options.cpp
new file mode 100644
index 000000000000..ffa4bca5a09d
--- /dev/null
+++ b/compiler-rt/lib/gwp_asan/tests/options.cpp
@@ -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");
+}
diff --git a/compiler-rt/lib/scudo/scudo_allocator.cpp b/compiler-rt/lib/scudo/scudo_allocator.cpp
index 954e51bdee63..82864405dfb0 100644
--- a/compiler-rt/lib/scudo/scudo_allocator.cpp
+++ b/compiler-rt/lib/scudo/scudo_allocator.cpp
@@ -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);
diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt
index dfae6dde5e4d..52063f4581d4 100644
--- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt
@@ -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()
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 11370be3fb4a..0df7a652ffa5 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -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 @@ class Allocator {
// 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.
diff --git a/compiler-rt/lib/scudo/standalone/flags.cpp b/compiler-rt/lib/scudo/standalone/flags.cpp
index de5153b288b1..285143a5d6bb 100644
--- a/compiler-rt/lib/scudo/standalone/flags.cpp
+++ b/compiler-rt/lib/scudo/standalone/flags.cpp
@@ -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() {
diff --git a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
index 78c297ae7e80..4c2164e1c689 100644
--- a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
@@ -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)
diff --git a/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp b/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
index 0205052edd26..45918ad4d2ca 100644
--- a/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/flags_test.cpp
@@ -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
diff --git a/compiler-rt/test/scudo/standalone/unit/lit.site.cfg.py.in b/compiler-rt/test/scudo/standalone/unit/lit.site.cfg.py.in
index 67a31973d15e..d6deb67aaa3c 100644
--- a/compiler-rt/test/scudo/standalone/unit/lit.site.cfg.py.in
+++ b/compiler-rt/test/scudo/standalone/unit/lit.site.cfg.py.in
@@ -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'
diff --git a/compiler-rt/tools/gwp_asan/CMakeLists.txt b/compiler-rt/tools/gwp_asan/CMakeLists.txt
index b0f9f0cf9e5d..4dc27cf5d7dd 100644
--- a/compiler-rt/tools/gwp_asan/CMakeLists.txt
+++ b/compiler-rt/tools/gwp_asan/CMakeLists.txt
@@ -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()
diff --git a/compiler-rt/tools/gwp_asan/options_parser_fuzzer.cpp b/compiler-rt/tools/gwp_asan/options_parser_fuzzer.cpp
new file mode 100644
index 000000000000..2d87f12c14f1
--- /dev/null
+++ b/compiler-rt/tools/gwp_asan/options_parser_fuzzer.cpp
@@ -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;
+}
More information about the llvm-branch-commits
mailing list