[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
This commit is contained in:
parent
c33944832c
commit
2133daf232
|
@ -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)
|
||||
|
|
|
@ -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 <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);
|
||||
#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
|
|
@ -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_
|
|
@ -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_
|
|
@ -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.")
|
Loading…
Reference in New Issue