From 2133daf232c5ee8f9cee5662e5b31f584992d3a6 Mon Sep 17 00:00:00 2001 From: Mitch Phillips Date: Tue, 4 Jun 2019 17:01:11 +0000 Subject: [PATCH] [GWP-ASan] Configuration options [3]. Summary: See D60593 for further information. This patch introduces the configuration options for GWP-ASan. In general, we expect the supporting allocator to populate the options struct, and give that to GWP-ASan during initialisation. For allocators that are okay with pulling in sanitizer_common, we also provide an optional parser that populates the gwp_asan::Options struct with values provided in the GWP_ASAN_OPTIONS environment variable. This patch contains very little logic, and all of the testable components (i.e. the optional parser's internal logic) is tested as part of the sanitizer_common testbed. Reviewers: vlad.tsyrklevich, morehouse, jfb Reviewed By: morehouse Subscribers: dexonsmith, kubamracek, mgorny, #sanitizers, llvm-commits, vitalybuka Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D62698 llvm-svn: 362527 --- compiler-rt/lib/gwp_asan/CMakeLists.txt | 48 ++++++++++++ .../lib/gwp_asan/optional/options_parser.cpp | 91 ++++++++++++++++++++++ compiler-rt/lib/gwp_asan/optional/options_parser.h | 32 ++++++++ compiler-rt/lib/gwp_asan/options.h | 41 ++++++++++ compiler-rt/lib/gwp_asan/options.inc | 41 ++++++++++ 5 files changed, 253 insertions(+) create mode 100644 compiler-rt/lib/gwp_asan/optional/options_parser.cpp create mode 100644 compiler-rt/lib/gwp_asan/optional/options_parser.h create mode 100644 compiler-rt/lib/gwp_asan/options.h create mode 100644 compiler-rt/lib/gwp_asan/options.inc diff --git a/compiler-rt/lib/gwp_asan/CMakeLists.txt b/compiler-rt/lib/gwp_asan/CMakeLists.txt index 6c83d86c..771192f 100644 --- a/compiler-rt/lib/gwp_asan/CMakeLists.txt +++ b/compiler-rt/lib/gwp_asan/CMakeLists.txt @@ -10,6 +10,8 @@ set(GWP_ASAN_SOURCES set(GWP_ASAN_HEADERS mutex.h random.h + options.h + options.inc ) # Ensure that GWP-ASan meets the delegated requirements of some supporting @@ -20,6 +22,26 @@ set(GWP_ASAN_CFLAGS -fno-rtti -fno-exceptions -nostdinc++ -pthread) # 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. +set(GWP_ASAN_OPTIONS_PARSER_SOURCES + optional/options_parser.cpp +) +set(GWP_ASAN_OPTIONS_PARSER_HEADERS + optional/options_parser.h + options.h + options.inc +) +set(GWP_ASAN_OPTIONS_PARSER_CFLAGS + ${GWP_ASAN_CFLAGS} + ${SANITIZER_COMMON_CFLAGS}) +set(GWP_ASAN_OPTIONS_PARSER_OBJECT_LIBS + RTSanitizerCommon + RTSanitizerCommonNoLibc) + if (COMPILER_RT_HAS_GWP_ASAN) foreach(arch ${GWP_ASAN_SUPPORTED_ARCH}) add_compiler_rt_runtime( @@ -38,6 +60,32 @@ if (COMPILER_RT_HAS_GWP_ASAN) SOURCES ${GWP_ASAN_SOURCES} 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'). + add_compiler_rt_object_libraries(RTGwpAsanOptionsParser + ARCHS ${GWP_ASAN_SUPPORTED_ARCH} + SOURCES ${GWP_ASAN_OPTIONS_PARSER_SOURCES} + ADDITIONAL_HEADERS ${GWP_ASAN_OPTIONS_PARSER_HEADERS} + CFLAGS ${GWP_ASAN_OPTIONS_PARSER_CFLAGS}) + + # Ensure that the build for the options parser succeeds, as + # 'RTGwpAsanOptionsParser' may not be built if it's not needed. This library + # has only a very small amount of logic, all of the testable components are + # exercised in the sanitizer_common test suite. + foreach(arch ${GWP_ASAN_SUPPORTED_ARCH}) + add_compiler_rt_runtime( + clang_rt.gwp_asan_options_parser + SHARED + ARCHS ${arch} + SOURCES ${GWP_ASAN_OPTIONS_PARSER_SOURCES} + ADDITIONAL_HEADERS ${GWP_ASAN_OPTIONS_PARSER_HEADERS} + CFLAGS ${GWP_ASAN_OPTIONS_PARSER_CFLAGS} + OBJECT_LIBS ${GWP_ASAN_OPTIONS_PARSER_OBJECT_LIBS} + PARENT_TARGET gwp_asan + ) + endforeach() endif() if(COMPILER_RT_INCLUDE_TESTS) diff --git a/compiler-rt/lib/gwp_asan/optional/options_parser.cpp b/compiler-rt/lib/gwp_asan/optional/options_parser.cpp new file mode 100644 index 0000000..ba9af49 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/optional/options_parser.cpp @@ -0,0 +1,91 @@ +//===-- options_parser.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/optional/options_parser.h" + +#include +#include +#include +#include + +#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); +#include "gwp_asan/options.inc" +#undef GWP_ASAN_OPTION +} + +const char *getCompileDefinitionGwpAsanDefaultOptions() { +#ifdef GWP_ASAN_DEFAULT_OPTIONS + return SANITIZER_STRINGIFY(GWP_ASAN_DEFAULT_OPTIONS); +#else + return ""; +#endif +} + +const char *getGwpAsanDefaultOptions() { + return (__gwp_asan_default_options) ? __gwp_asan_default_options() : ""; +} + +Options *getOptionsInternal() { + static Options GwpAsanFlags; + return &GwpAsanFlags; +} +} // anonymous namespace + +void initOptions() { + Options *o = getOptionsInternal(); + o->setDefaults(); + + __sanitizer::FlagParser Parser; + registerGwpAsanFlags(&Parser, o); + + // Override from compile definition. + Parser.ParseString(getCompileDefinitionGwpAsanDefaultOptions()); + + // Override from user-specified string. + Parser.ParseString(getGwpAsanDefaultOptions()); + + // Override from environment. + Parser.ParseString(__sanitizer::GetEnv("GWP_ASAN_OPTIONS")); + + __sanitizer::InitializeCommonFlags(); + if (__sanitizer::Verbosity()) + __sanitizer::ReportUnrecognizedFlags(); + + 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); + } + + if (o->SampleRate < 1) { + __sanitizer::Printf( + "GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n"); + exit(EXIT_FAILURE); + } + + o->Printf = __sanitizer::Printf; +} + +const Options &getOptions() { return *getOptionsInternal(); } + +} // namespace options +} // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/optional/options_parser.h b/compiler-rt/lib/gwp_asan/optional/options_parser.h new file mode 100644 index 0000000..7a1d3b0 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/optional/options_parser.h @@ -0,0 +1,32 @@ +//===-- options_parser.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_ +#define GWP_ASAN_OPTIONAL_OPTIONS_PARSER_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(); +// Returns a pointer to the initialised options. Call initOptions() prior to +// calling this function. +const Options &getOptions(); + +} // namespace options +} // namespace gwp_asan + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char * +__gwp_asan_default_options(); +} + +#endif // GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_ diff --git a/compiler-rt/lib/gwp_asan/options.h b/compiler-rt/lib/gwp_asan/options.h new file mode 100644 index 0000000..c1b6e67 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/options.h @@ -0,0 +1,41 @@ +//===-- options.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef GWP_ASAN_OPTIONS_H_ +#define GWP_ASAN_OPTIONS_H_ + +namespace gwp_asan { +namespace options { +// The function pointer type for printf(). Follows the standard format from the +// sanitizers library. If the supported allocator exposes printing via a +// different function signature, please provide a wrapper which has this +// printf() signature, and pass the wrapper instead. +typedef void (*Printf_t)(const char *Format, ...); + +struct Options { + Printf_t Printf = nullptr; + + // Read the options from the included definitions file. +#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \ + Type Name = DefaultValue; +#include "gwp_asan/options.inc" +#undef GWP_ASAN_OPTION + + void setDefaults() { +#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \ + Name = DefaultValue; +#include "gwp_asan/options.inc" +#undef GWP_ASAN_OPTION + + Printf = nullptr; + } +}; +} // namespace options +} // namespace gwp_asan + +#endif // GWP_ASAN_OPTIONS_H_ diff --git a/compiler-rt/lib/gwp_asan/options.inc b/compiler-rt/lib/gwp_asan/options.inc new file mode 100644 index 0000000..9042b11 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/options.inc @@ -0,0 +1,41 @@ +//===-- options.inc ---------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef GWP_ASAN_OPTION +#error "Define GWP_ASAN_OPTION prior to including this file!" +#endif + +GWP_ASAN_OPTION(bool, Enabled, true, "Is GWP-ASan enabled? Defaults to true.") + +GWP_ASAN_OPTION( + bool, PerfectlyRightAlign, false, + "When allocations are right-aligned, should we perfectly align them up to " + "the page boundary? By default (false), we round up allocation size to the " + "nearest power of two (1, 2, 4, 8, 16) up to a maximum of 16-byte " + "alignment for performance reasons. Setting this to true can find single " + "byte buffer-overflows for multibyte allocations at the cost of " + "performance, and may be incompatible with some architectures.") + +GWP_ASAN_OPTION( + int, MaxSimultaneousAllocations, 16, + "Number of usable guarded slots in the allocation pool. Defaults to 16.") + +GWP_ASAN_OPTION(int, SampleRate, 5000, + "The probability (1 / SampleRate) that an allocation is " + "selected for GWP-ASan sampling. Default is 5000. Sample rates " + "up to (2^31 - 1) are supported.") + +GWP_ASAN_OPTION( + bool, InstallSignalHandlers, true, + "Install GWP-ASan signal handlers for SIGSEGV during dynamic loading. This " + "allows better error reports by providing stack traces for allocation and " + "deallocation when reporting a memory error. GWP-ASan's signal handler " + "will forward the signal to any previously-installed handler, and user " + "programs that install further signal handlers should make sure they do " + "the same. Note, if the previously installed SIGSEGV handler is SIG_IGN, " + "we terminate the process after dumping the error report.") -- 2.7.4