forked from OSchip/llvm-project
[GWP-ASan] Minor refactor of optional components.
In preparation for the inbuilt options parser, this is a minor refactor of optional components including: - Putting certain optional elements in the right header files, according to their function and their dependencies. - Cleaning up some old and mostly-dead code. - Moving some functions into anonymous namespaces to prevent symbol export. Reviewed By: cryptoad, eugenis Differential Revision: https://reviews.llvm.org/D94117
This commit is contained in:
parent
64e9e9aeee
commit
a8520f6970
|
@ -9,21 +9,45 @@
|
||||||
#ifndef GWP_ASAN_OPTIONAL_BACKTRACE_H_
|
#ifndef GWP_ASAN_OPTIONAL_BACKTRACE_H_
|
||||||
#define GWP_ASAN_OPTIONAL_BACKTRACE_H_
|
#define GWP_ASAN_OPTIONAL_BACKTRACE_H_
|
||||||
|
|
||||||
#include "gwp_asan/optional/segv_handler.h"
|
#include "gwp_asan/optional/printf.h"
|
||||||
#include "gwp_asan/options.h"
|
#include "gwp_asan/options.h"
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace options {
|
namespace backtrace {
|
||||||
// Functions to get the platform-specific and implementation-specific backtrace
|
// ================================ Description ================================
|
||||||
// and backtrace printing functions when RTGwpAsanBacktraceLibc or
|
// This function shall take the backtrace provided in `TraceBuffer`, and print
|
||||||
// RTGwpAsanBacktraceSanitizerCommon are linked. Use these functions to get the
|
// it in a human-readable format using `Print`. Generally, this function shall
|
||||||
// backtrace function for populating the Options::Backtrace and
|
// resolve raw pointers to section offsets and print them with the following
|
||||||
// Options::PrintBacktrace when initialising the GuardedPoolAllocator. Please
|
// sanitizer-common format:
|
||||||
// note any thread-safety descriptions for the implementation of these functions
|
// " #{frame_number} {pointer} in {function name} ({binary name}+{offset}"
|
||||||
// that you use.
|
// e.g. " #5 0x420459 in _start (/tmp/uaf+0x420459)"
|
||||||
Backtrace_t getBacktraceFunction();
|
// This format allows the backtrace to be symbolized offline successfully using
|
||||||
crash_handler::PrintBacktrace_t getPrintBacktraceFunction();
|
// llvm-symbolizer.
|
||||||
} // namespace options
|
// =================================== Notes ===================================
|
||||||
|
// This function may directly or indirectly call malloc(), as the
|
||||||
|
// GuardedPoolAllocator contains a reentrancy barrier to prevent infinite
|
||||||
|
// recursion. Any allocation made inside this function will be served by the
|
||||||
|
// supporting allocator, and will not have GWP-ASan protections.
|
||||||
|
typedef void (*PrintBacktrace_t)(uintptr_t *TraceBuffer, size_t TraceLength,
|
||||||
|
Printf_t Print);
|
||||||
|
|
||||||
|
// Returns a function pointer to a backtrace function that's suitable for
|
||||||
|
// unwinding through a signal handler. This is important primarily for frame-
|
||||||
|
// pointer based unwinders, DWARF or other unwinders can simply provide the
|
||||||
|
// normal backtrace function as the implementation here. On POSIX, SignalContext
|
||||||
|
// should be the `ucontext_t` from the signal handler.
|
||||||
|
typedef size_t (*SegvBacktrace_t)(uintptr_t *TraceBuffer, size_t Size,
|
||||||
|
void *SignalContext);
|
||||||
|
|
||||||
|
// Returns platform-specific provided implementations of Backtrace_t for use
|
||||||
|
// inside the GWP-ASan core allocator.
|
||||||
|
options::Backtrace_t getBacktraceFunction();
|
||||||
|
|
||||||
|
// Returns platform-specific provided implementations of PrintBacktrace_t and
|
||||||
|
// SegvBacktrace_t for use in the optional SEGV handler.
|
||||||
|
PrintBacktrace_t getPrintBacktraceFunction();
|
||||||
|
SegvBacktrace_t getSegvBacktraceFunction();
|
||||||
|
} // namespace backtrace
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
||||||
#endif // GWP_ASAN_OPTIONAL_BACKTRACE_H_
|
#endif // GWP_ASAN_OPTIONAL_BACKTRACE_H_
|
||||||
|
|
|
@ -11,12 +11,11 @@
|
||||||
// GWP-ASan on Fuchsia doesn't currently support backtraces.
|
// GWP-ASan on Fuchsia doesn't currently support backtraces.
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace options {
|
namespace backtrace {
|
||||||
Backtrace_t getBacktraceFunction() { return nullptr; }
|
|
||||||
crash_handler::PrintBacktrace_t getPrintBacktraceFunction() { return nullptr; }
|
|
||||||
} // namespace options
|
|
||||||
|
|
||||||
namespace crash_handler {
|
options::Backtrace_t getBacktraceFunction() { return nullptr; }
|
||||||
|
PrintBacktrace_t getPrintBacktraceFunction() { return nullptr; }
|
||||||
SegvBacktrace_t getSegvBacktraceFunction() { return nullptr; }
|
SegvBacktrace_t getSegvBacktraceFunction() { return nullptr; }
|
||||||
} // namespace crash_handler
|
|
||||||
|
} // namespace backtrace
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gwp_asan/definitions.h"
|
||||||
#include "gwp_asan/optional/backtrace.h"
|
#include "gwp_asan/optional/backtrace.h"
|
||||||
|
#include "gwp_asan/optional/printf.h"
|
||||||
#include "gwp_asan/options.h"
|
#include "gwp_asan/options.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -32,7 +34,7 @@ GWP_ASAN_ALWAYS_INLINE size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
|
static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
|
||||||
gwp_asan::crash_handler::Printf_t Printf) {
|
gwp_asan::Printf_t Printf) {
|
||||||
if (TraceLength == 0) {
|
if (TraceLength == 0) {
|
||||||
Printf(" <not found (does your allocator support backtracing?)>\n\n");
|
Printf(" <not found (does your allocator support backtracing?)>\n\n");
|
||||||
return;
|
return;
|
||||||
|
@ -55,14 +57,11 @@ static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace options {
|
namespace backtrace {
|
||||||
Backtrace_t getBacktraceFunction() { return Backtrace; }
|
|
||||||
crash_handler::PrintBacktrace_t getPrintBacktraceFunction() {
|
|
||||||
return PrintBacktrace;
|
|
||||||
}
|
|
||||||
} // namespace options
|
|
||||||
|
|
||||||
namespace crash_handler {
|
options::Backtrace_t getBacktraceFunction() { return Backtrace; }
|
||||||
|
PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
|
||||||
SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
|
SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
|
||||||
} // namespace crash_handler
|
|
||||||
|
} // namespace backtrace
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
|
@ -62,7 +62,7 @@ size_t SegvBacktrace(uintptr_t *TraceBuffer, size_t Size, void *Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
|
static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
|
||||||
gwp_asan::crash_handler::Printf_t Printf) {
|
gwp_asan::Printf_t Printf) {
|
||||||
__sanitizer::StackTrace StackTrace;
|
__sanitizer::StackTrace StackTrace;
|
||||||
StackTrace.trace = reinterpret_cast<__sanitizer::uptr *>(Trace);
|
StackTrace.trace = reinterpret_cast<__sanitizer::uptr *>(Trace);
|
||||||
StackTrace.size = TraceLength;
|
StackTrace.size = TraceLength;
|
||||||
|
@ -77,25 +77,23 @@ static void PrintBacktrace(uintptr_t *Trace, size_t TraceLength,
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace options {
|
namespace backtrace {
|
||||||
|
|
||||||
// This function is thread-compatible. It must be synchronised in respect to any
|
// This function is thread-compatible. It must be synchronised in respect to any
|
||||||
// other calls to getBacktraceFunction(), calls to getPrintBacktraceFunction(),
|
// other calls to getBacktraceFunction(), calls to getPrintBacktraceFunction(),
|
||||||
// and calls to either of the functions that they return. Furthermore, this may
|
// and calls to either of the functions that they return. Furthermore, this may
|
||||||
// require synchronisation with any calls to sanitizer_common that use flags.
|
// require synchronisation with any calls to sanitizer_common that use flags.
|
||||||
// Generally, this function will be called during the initialisation of the
|
// Generally, this function will be called during the initialisation of the
|
||||||
// allocator, which is done in a thread-compatible manner.
|
// allocator, which is done in a thread-compatible manner.
|
||||||
Backtrace_t getBacktraceFunction() {
|
options::Backtrace_t getBacktraceFunction() {
|
||||||
// The unwinder requires the default flags to be set.
|
// The unwinder requires the default flags to be set.
|
||||||
__sanitizer::SetCommonFlagsDefaults();
|
__sanitizer::SetCommonFlagsDefaults();
|
||||||
__sanitizer::InitializeCommonFlags();
|
__sanitizer::InitializeCommonFlags();
|
||||||
return Backtrace;
|
return Backtrace;
|
||||||
}
|
}
|
||||||
crash_handler::PrintBacktrace_t getPrintBacktraceFunction() {
|
|
||||||
return PrintBacktrace;
|
|
||||||
}
|
|
||||||
} // namespace options
|
|
||||||
|
|
||||||
namespace crash_handler {
|
PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
|
||||||
SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
|
SegvBacktrace_t getSegvBacktraceFunction() { return SegvBacktrace; }
|
||||||
} // namespace crash_handler
|
|
||||||
|
} // namespace backtrace
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
//===-- printf.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_PRINTF_H_
|
||||||
|
#define GWP_ASAN_OPTIONAL_PRINTF_H_
|
||||||
|
|
||||||
|
namespace gwp_asan {
|
||||||
|
|
||||||
|
// ================================ Requirements ===============================
|
||||||
|
// This function is required to be provided by the supporting allocator iff the
|
||||||
|
// allocator wants to use any of the optional components.
|
||||||
|
// ================================ Description ================================
|
||||||
|
// This function shall produce output according to a strict subset of the C
|
||||||
|
// standard library's printf() family. This function must support printing the
|
||||||
|
// following formats:
|
||||||
|
// 1. integers: "%([0-9]*)?(z|ll)?{d,u,x,X}"
|
||||||
|
// 2. pointers: "%p"
|
||||||
|
// 3. strings: "%[-]([0-9]*)?(\\.\\*)?s"
|
||||||
|
// 4. chars: "%c"
|
||||||
|
// This function must be implemented in a signal-safe manner, and thus must not
|
||||||
|
// malloc().
|
||||||
|
// =================================== Notes ===================================
|
||||||
|
// This function has a slightly different signature than the C standard
|
||||||
|
// library's printf(). Notably, it returns 'void' rather than 'int'.
|
||||||
|
typedef void (*Printf_t)(const char *Format, ...);
|
||||||
|
|
||||||
|
} // namespace gwp_asan
|
||||||
|
#endif // GWP_ASAN_OPTIONAL_PRINTF_H_
|
|
@ -10,64 +10,11 @@
|
||||||
#define GWP_ASAN_OPTIONAL_SEGV_HANDLER_H_
|
#define GWP_ASAN_OPTIONAL_SEGV_HANDLER_H_
|
||||||
|
|
||||||
#include "gwp_asan/guarded_pool_allocator.h"
|
#include "gwp_asan/guarded_pool_allocator.h"
|
||||||
#include "gwp_asan/options.h"
|
#include "gwp_asan/optional/backtrace.h"
|
||||||
|
#include "gwp_asan/optional/printf.h"
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace crash_handler {
|
namespace segv_handler {
|
||||||
// ================================ Requirements ===============================
|
|
||||||
// This function must be provided by the supporting allocator only when this
|
|
||||||
// provided crash handler is used to dump the generic report.
|
|
||||||
// sanitizer::Printf() function can be simply used here.
|
|
||||||
// ================================ Description ================================
|
|
||||||
// This function shall produce output according to a strict subset of the C
|
|
||||||
// standard library's printf() family. This function must support printing the
|
|
||||||
// following formats:
|
|
||||||
// 1. integers: "%([0-9]*)?(z|ll)?{d,u,x,X}"
|
|
||||||
// 2. pointers: "%p"
|
|
||||||
// 3. strings: "%[-]([0-9]*)?(\\.\\*)?s"
|
|
||||||
// 4. chars: "%c"
|
|
||||||
// This function must be implemented in a signal-safe manner, and thus must not
|
|
||||||
// malloc().
|
|
||||||
// =================================== Notes ===================================
|
|
||||||
// This function has a slightly different signature than the C standard
|
|
||||||
// library's printf(). Notably, it returns 'void' rather than 'int'.
|
|
||||||
typedef void (*Printf_t)(const char *Format, ...);
|
|
||||||
|
|
||||||
// ================================ Requirements ===============================
|
|
||||||
// This function is required for the supporting allocator, but one of the three
|
|
||||||
// provided implementations may be used (RTGwpAsanBacktraceLibc,
|
|
||||||
// RTGwpAsanBacktraceSanitizerCommon, or BasicPrintBacktraceFunction).
|
|
||||||
// ================================ Description ================================
|
|
||||||
// This function shall take the backtrace provided in `TraceBuffer`, and print
|
|
||||||
// it in a human-readable format using `Print`. Generally, this function shall
|
|
||||||
// resolve raw pointers to section offsets and print them with the following
|
|
||||||
// sanitizer-common format:
|
|
||||||
// " #{frame_number} {pointer} in {function name} ({binary name}+{offset}"
|
|
||||||
// e.g. " #5 0x420459 in _start (/tmp/uaf+0x420459)"
|
|
||||||
// This format allows the backtrace to be symbolized offline successfully using
|
|
||||||
// llvm-symbolizer.
|
|
||||||
// =================================== Notes ===================================
|
|
||||||
// This function may directly or indirectly call malloc(), as the
|
|
||||||
// GuardedPoolAllocator contains a reentrancy barrier to prevent infinite
|
|
||||||
// recursion. Any allocation made inside this function will be served by the
|
|
||||||
// supporting allocator, and will not have GWP-ASan protections.
|
|
||||||
typedef void (*PrintBacktrace_t)(uintptr_t *TraceBuffer, size_t TraceLength,
|
|
||||||
Printf_t Print);
|
|
||||||
|
|
||||||
// Returns a function pointer to a basic PrintBacktrace implementation. This
|
|
||||||
// implementation simply prints the stack trace in a human readable fashion
|
|
||||||
// without any symbolization.
|
|
||||||
PrintBacktrace_t getBasicPrintBacktraceFunction();
|
|
||||||
|
|
||||||
// Returns a function pointer to a backtrace function that's suitable for
|
|
||||||
// unwinding through a signal handler. This is important primarily for frame-
|
|
||||||
// pointer based unwinders, DWARF or other unwinders can simply provide the
|
|
||||||
// normal backtrace function as the implementation here. On POSIX, SignalContext
|
|
||||||
// should be the `ucontext_t` from the signal handler.
|
|
||||||
typedef size_t (*SegvBacktrace_t)(uintptr_t *TraceBuffer, size_t Size,
|
|
||||||
void *SignalContext);
|
|
||||||
SegvBacktrace_t getSegvBacktraceFunction();
|
|
||||||
|
|
||||||
// Install the SIGSEGV crash handler for printing use-after-free and heap-
|
// Install the SIGSEGV crash handler for printing use-after-free and heap-
|
||||||
// buffer-{under|over}flow exceptions if the user asked for it. This is platform
|
// buffer-{under|over}flow exceptions if the user asked for it. This is platform
|
||||||
// specific as even though POSIX and Windows both support registering handlers
|
// specific as even though POSIX and Windows both support registering handlers
|
||||||
|
@ -75,16 +22,12 @@ SegvBacktrace_t getSegvBacktraceFunction();
|
||||||
// the address that caused the SIGSEGV exception. GPA->init() must be called
|
// the address that caused the SIGSEGV exception. GPA->init() must be called
|
||||||
// before this function.
|
// before this function.
|
||||||
void installSignalHandlers(gwp_asan::GuardedPoolAllocator *GPA, Printf_t Printf,
|
void installSignalHandlers(gwp_asan::GuardedPoolAllocator *GPA, Printf_t Printf,
|
||||||
PrintBacktrace_t PrintBacktrace,
|
gwp_asan::backtrace::PrintBacktrace_t PrintBacktrace,
|
||||||
SegvBacktrace_t SegvBacktrace);
|
gwp_asan::backtrace::SegvBacktrace_t SegvBacktrace);
|
||||||
|
|
||||||
|
// Uninistall the signal handlers, test-only.
|
||||||
void uninstallSignalHandlers();
|
void uninstallSignalHandlers();
|
||||||
|
} // namespace segv_handler
|
||||||
void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
|
|
||||||
const gwp_asan::AllocationMetadata *Metadata,
|
|
||||||
SegvBacktrace_t SegvBacktrace, Printf_t Printf,
|
|
||||||
PrintBacktrace_t PrintBacktrace, void *Context);
|
|
||||||
} // namespace crash_handler
|
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
||||||
#endif // GWP_ASAN_OPTIONAL_SEGV_HANDLER_H_
|
#endif // GWP_ASAN_OPTIONAL_SEGV_HANDLER_H_
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
// GWP-ASan on Fuchsia doesn't currently support signal handlers.
|
// GWP-ASan on Fuchsia doesn't currently support signal handlers.
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace crash_handler {
|
namespace segv_handler {
|
||||||
void installSignalHandlers(gwp_asan::GuardedPoolAllocator * /* GPA */,
|
void installSignalHandlers(gwp_asan::GuardedPoolAllocator * /* GPA */,
|
||||||
Printf_t /* Printf */,
|
Printf_t /* Printf */,
|
||||||
PrintBacktrace_t /* PrintBacktrace */,
|
backtrace::PrintBacktrace_t /* PrintBacktrace */,
|
||||||
SegvBacktrace_t /* SegvBacktrace */) {}
|
backtrace::SegvBacktrace_t /* SegvBacktrace */) {}
|
||||||
|
|
||||||
void uninstallSignalHandlers() {}
|
void uninstallSignalHandlers() {}
|
||||||
} // namespace crash_handler
|
} // namespace segv_handler
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
|
@ -12,62 +12,30 @@
|
||||||
#include "gwp_asan/optional/segv_handler.h"
|
#include "gwp_asan/optional/segv_handler.h"
|
||||||
#include "gwp_asan/options.h"
|
#include "gwp_asan/options.h"
|
||||||
|
|
||||||
|
// RHEL creates the PRIu64 format macro (for printing uint64_t's) only when this
|
||||||
|
// macro is defined before including <inttypes.h>.
|
||||||
|
#ifndef __STDC_FORMAT_MACROS
|
||||||
|
#define __STDC_FORMAT_MACROS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace {
|
|
||||||
using gwp_asan::AllocationMetadata;
|
using gwp_asan::AllocationMetadata;
|
||||||
using gwp_asan::Error;
|
using gwp_asan::Error;
|
||||||
using gwp_asan::GuardedPoolAllocator;
|
using gwp_asan::GuardedPoolAllocator;
|
||||||
using gwp_asan::crash_handler::PrintBacktrace_t;
|
using gwp_asan::Printf_t;
|
||||||
using gwp_asan::crash_handler::Printf_t;
|
using gwp_asan::backtrace::PrintBacktrace_t;
|
||||||
using gwp_asan::crash_handler::SegvBacktrace_t;
|
using gwp_asan::backtrace::SegvBacktrace_t;
|
||||||
|
|
||||||
struct sigaction PreviousHandler;
|
namespace {
|
||||||
bool SignalHandlerInstalled;
|
|
||||||
gwp_asan::GuardedPoolAllocator *GPAForSignalHandler;
|
|
||||||
Printf_t PrintfForSignalHandler;
|
|
||||||
PrintBacktrace_t PrintBacktraceForSignalHandler;
|
|
||||||
SegvBacktrace_t BacktraceForSignalHandler;
|
|
||||||
|
|
||||||
static void sigSegvHandler(int sig, siginfo_t *info, void *ucontext) {
|
|
||||||
if (GPAForSignalHandler) {
|
|
||||||
GPAForSignalHandler->stop();
|
|
||||||
|
|
||||||
gwp_asan::crash_handler::dumpReport(
|
|
||||||
reinterpret_cast<uintptr_t>(info->si_addr),
|
|
||||||
GPAForSignalHandler->getAllocatorState(),
|
|
||||||
GPAForSignalHandler->getMetadataRegion(), BacktraceForSignalHandler,
|
|
||||||
PrintfForSignalHandler, PrintBacktraceForSignalHandler, ucontext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process any previous handlers.
|
|
||||||
if (PreviousHandler.sa_flags & SA_SIGINFO) {
|
|
||||||
PreviousHandler.sa_sigaction(sig, info, ucontext);
|
|
||||||
} else if (PreviousHandler.sa_handler == SIG_DFL) {
|
|
||||||
// If the previous handler was the default handler, cause a core dump.
|
|
||||||
signal(SIGSEGV, SIG_DFL);
|
|
||||||
raise(SIGSEGV);
|
|
||||||
} else if (PreviousHandler.sa_handler == SIG_IGN) {
|
|
||||||
// If the previous segv handler was SIGIGN, crash iff we were responsible
|
|
||||||
// for the crash.
|
|
||||||
if (__gwp_asan_error_is_mine(GPAForSignalHandler->getAllocatorState(),
|
|
||||||
reinterpret_cast<uintptr_t>(info->si_addr))) {
|
|
||||||
signal(SIGSEGV, SIG_DFL);
|
|
||||||
raise(SIGSEGV);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PreviousHandler.sa_handler(sig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ScopedEndOfReportDecorator {
|
struct ScopedEndOfReportDecorator {
|
||||||
ScopedEndOfReportDecorator(gwp_asan::crash_handler::Printf_t Printf)
|
ScopedEndOfReportDecorator(gwp_asan::Printf_t Printf) : Printf(Printf) {}
|
||||||
: Printf(Printf) {}
|
|
||||||
~ScopedEndOfReportDecorator() { Printf("*** End GWP-ASan report ***\n"); }
|
~ScopedEndOfReportDecorator() { Printf("*** End GWP-ASan report ***\n"); }
|
||||||
gwp_asan::crash_handler::Printf_t Printf;
|
gwp_asan::Printf_t Printf;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prints the provided error and metadata information.
|
// Prints the provided error and metadata information.
|
||||||
|
@ -117,47 +85,6 @@ void printHeader(Error E, uintptr_t AccessPtr,
|
||||||
AccessPtr, DescriptionBuffer, ThreadBuffer);
|
AccessPtr, DescriptionBuffer, ThreadBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void defaultPrintStackTrace(uintptr_t *Trace, size_t TraceLength,
|
|
||||||
gwp_asan::crash_handler::Printf_t Printf) {
|
|
||||||
if (TraceLength == 0)
|
|
||||||
Printf(" <unknown (does your allocator support backtracing?)>\n");
|
|
||||||
|
|
||||||
for (size_t i = 0; i < TraceLength; ++i) {
|
|
||||||
Printf(" #%zu 0x%zx in <unknown>\n", i, Trace[i]);
|
|
||||||
}
|
|
||||||
Printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
namespace gwp_asan {
|
|
||||||
namespace crash_handler {
|
|
||||||
PrintBacktrace_t getBasicPrintBacktraceFunction() {
|
|
||||||
return defaultPrintStackTrace;
|
|
||||||
}
|
|
||||||
|
|
||||||
void installSignalHandlers(gwp_asan::GuardedPoolAllocator *GPA, Printf_t Printf,
|
|
||||||
PrintBacktrace_t PrintBacktrace,
|
|
||||||
SegvBacktrace_t SegvBacktrace) {
|
|
||||||
GPAForSignalHandler = GPA;
|
|
||||||
PrintfForSignalHandler = Printf;
|
|
||||||
PrintBacktraceForSignalHandler = PrintBacktrace;
|
|
||||||
BacktraceForSignalHandler = SegvBacktrace;
|
|
||||||
|
|
||||||
struct sigaction Action = {};
|
|
||||||
Action.sa_sigaction = sigSegvHandler;
|
|
||||||
Action.sa_flags = SA_SIGINFO;
|
|
||||||
sigaction(SIGSEGV, &Action, &PreviousHandler);
|
|
||||||
SignalHandlerInstalled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void uninstallSignalHandlers() {
|
|
||||||
if (SignalHandlerInstalled) {
|
|
||||||
sigaction(SIGSEGV, &PreviousHandler, nullptr);
|
|
||||||
SignalHandlerInstalled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
|
void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
|
||||||
const gwp_asan::AllocationMetadata *Metadata,
|
const gwp_asan::AllocationMetadata *Metadata,
|
||||||
SegvBacktrace_t SegvBacktrace, Printf_t Printf,
|
SegvBacktrace_t SegvBacktrace, Printf_t Printf,
|
||||||
|
@ -205,7 +132,7 @@ void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
|
||||||
// Maybe print the deallocation trace.
|
// Maybe print the deallocation trace.
|
||||||
if (__gwp_asan_is_deallocated(AllocMeta)) {
|
if (__gwp_asan_is_deallocated(AllocMeta)) {
|
||||||
uint64_t ThreadID = __gwp_asan_get_deallocation_thread_id(AllocMeta);
|
uint64_t ThreadID = __gwp_asan_get_deallocation_thread_id(AllocMeta);
|
||||||
if (ThreadID == kInvalidThreadID)
|
if (ThreadID == gwp_asan::kInvalidThreadID)
|
||||||
Printf("0x%zx was deallocated by thread <unknown> here:\n", ErrorPtr);
|
Printf("0x%zx was deallocated by thread <unknown> here:\n", ErrorPtr);
|
||||||
else
|
else
|
||||||
Printf("0x%zx was deallocated by thread %zu here:\n", ErrorPtr, ThreadID);
|
Printf("0x%zx was deallocated by thread %zu here:\n", ErrorPtr, ThreadID);
|
||||||
|
@ -216,7 +143,7 @@ void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
|
||||||
|
|
||||||
// Print the allocation trace.
|
// Print the allocation trace.
|
||||||
uint64_t ThreadID = __gwp_asan_get_allocation_thread_id(AllocMeta);
|
uint64_t ThreadID = __gwp_asan_get_allocation_thread_id(AllocMeta);
|
||||||
if (ThreadID == kInvalidThreadID)
|
if (ThreadID == gwp_asan::kInvalidThreadID)
|
||||||
Printf("0x%zx was allocated by thread <unknown> here:\n", ErrorPtr);
|
Printf("0x%zx was allocated by thread <unknown> here:\n", ErrorPtr);
|
||||||
else
|
else
|
||||||
Printf("0x%zx was allocated by thread %zu here:\n", ErrorPtr, ThreadID);
|
Printf("0x%zx was allocated by thread %zu here:\n", ErrorPtr, ThreadID);
|
||||||
|
@ -224,5 +151,75 @@ void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State,
|
||||||
AllocMeta, Trace, kMaximumStackFramesForCrashTrace);
|
AllocMeta, Trace, kMaximumStackFramesForCrashTrace);
|
||||||
PrintBacktrace(Trace, TraceLength, Printf);
|
PrintBacktrace(Trace, TraceLength, Printf);
|
||||||
}
|
}
|
||||||
} // namespace crash_handler
|
|
||||||
|
struct sigaction PreviousHandler;
|
||||||
|
bool SignalHandlerInstalled;
|
||||||
|
gwp_asan::GuardedPoolAllocator *GPAForSignalHandler;
|
||||||
|
Printf_t PrintfForSignalHandler;
|
||||||
|
PrintBacktrace_t PrintBacktraceForSignalHandler;
|
||||||
|
SegvBacktrace_t BacktraceForSignalHandler;
|
||||||
|
|
||||||
|
static void sigSegvHandler(int sig, siginfo_t *info, void *ucontext) {
|
||||||
|
if (GPAForSignalHandler) {
|
||||||
|
GPAForSignalHandler->stop();
|
||||||
|
|
||||||
|
dumpReport(reinterpret_cast<uintptr_t>(info->si_addr),
|
||||||
|
GPAForSignalHandler->getAllocatorState(),
|
||||||
|
GPAForSignalHandler->getMetadataRegion(),
|
||||||
|
BacktraceForSignalHandler, PrintfForSignalHandler,
|
||||||
|
PrintBacktraceForSignalHandler, ucontext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any previous handlers.
|
||||||
|
if (PreviousHandler.sa_flags & SA_SIGINFO) {
|
||||||
|
PreviousHandler.sa_sigaction(sig, info, ucontext);
|
||||||
|
} else if (PreviousHandler.sa_handler == SIG_DFL) {
|
||||||
|
// If the previous handler was the default handler, cause a core dump.
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
raise(SIGSEGV);
|
||||||
|
} else if (PreviousHandler.sa_handler == SIG_IGN) {
|
||||||
|
// If the previous segv handler was SIGIGN, crash iff we were responsible
|
||||||
|
// for the crash.
|
||||||
|
if (__gwp_asan_error_is_mine(GPAForSignalHandler->getAllocatorState(),
|
||||||
|
reinterpret_cast<uintptr_t>(info->si_addr))) {
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
raise(SIGSEGV);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PreviousHandler.sa_handler(sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
namespace gwp_asan {
|
||||||
|
namespace segv_handler {
|
||||||
|
|
||||||
|
void installSignalHandlers(gwp_asan::GuardedPoolAllocator *GPA, Printf_t Printf,
|
||||||
|
PrintBacktrace_t PrintBacktrace,
|
||||||
|
SegvBacktrace_t SegvBacktrace) {
|
||||||
|
assert(GPA && "GPA wasn't provided to installSignalHandlers.");
|
||||||
|
assert(Printf && "Printf wasn't provided to installSignalHandlers.");
|
||||||
|
assert(PrintBacktrace &&
|
||||||
|
"PrintBacktrace wasn't provided to installSignalHandlers.");
|
||||||
|
assert(SegvBacktrace &&
|
||||||
|
"SegvBacktrace wasn't provided to installSignalHandlers.");
|
||||||
|
GPAForSignalHandler = GPA;
|
||||||
|
PrintfForSignalHandler = Printf;
|
||||||
|
PrintBacktraceForSignalHandler = PrintBacktrace;
|
||||||
|
BacktraceForSignalHandler = SegvBacktrace;
|
||||||
|
|
||||||
|
struct sigaction Action = {};
|
||||||
|
Action.sa_sigaction = sigSegvHandler;
|
||||||
|
Action.sa_flags = SA_SIGINFO;
|
||||||
|
sigaction(SIGSEGV, &Action, &PreviousHandler);
|
||||||
|
SignalHandlerInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninstallSignalHandlers() {
|
||||||
|
if (SignalHandlerInstalled) {
|
||||||
|
sigaction(SIGSEGV, &PreviousHandler, nullptr);
|
||||||
|
SignalHandlerInstalled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace segv_handler
|
||||||
} // namespace gwp_asan
|
} // namespace gwp_asan
|
||||||
|
|
|
@ -10,7 +10,7 @@ set(GWP_ASAN_UNITTEST_CFLAGS
|
||||||
|
|
||||||
file(GLOB GWP_ASAN_HEADERS ../*.h)
|
file(GLOB GWP_ASAN_HEADERS ../*.h)
|
||||||
set(GWP_ASAN_UNITTESTS
|
set(GWP_ASAN_UNITTESTS
|
||||||
optional/printf_sanitizer_common.cpp
|
platform_specific/printf_sanitizer_common.cpp
|
||||||
alignment.cpp
|
alignment.cpp
|
||||||
backtrace.cpp
|
backtrace.cpp
|
||||||
basic.cpp
|
basic.cpp
|
||||||
|
|
|
@ -21,6 +21,7 @@ using Test = ::testing::Test;
|
||||||
|
|
||||||
#include "gwp_asan/guarded_pool_allocator.h"
|
#include "gwp_asan/guarded_pool_allocator.h"
|
||||||
#include "gwp_asan/optional/backtrace.h"
|
#include "gwp_asan/optional/backtrace.h"
|
||||||
|
#include "gwp_asan/optional/printf.h"
|
||||||
#include "gwp_asan/optional/segv_handler.h"
|
#include "gwp_asan/optional/segv_handler.h"
|
||||||
#include "gwp_asan/options.h"
|
#include "gwp_asan/options.h"
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ namespace test {
|
||||||
// their own signal-safe Printf function. In LLVM, we use
|
// their own signal-safe Printf function. In LLVM, we use
|
||||||
// `optional/printf_sanitizer_common.cpp` which supplies the __sanitizer::Printf
|
// `optional/printf_sanitizer_common.cpp` which supplies the __sanitizer::Printf
|
||||||
// for this purpose.
|
// for this purpose.
|
||||||
crash_handler::Printf_t getPrintfFunction();
|
Printf_t getPrintfFunction();
|
||||||
|
|
||||||
// First call returns true, all the following calls return false.
|
// First call returns true, all the following calls return false.
|
||||||
bool OnlyOnce();
|
bool OnlyOnce();
|
||||||
|
@ -86,19 +87,19 @@ public:
|
||||||
gwp_asan::options::Options Opts;
|
gwp_asan::options::Options Opts;
|
||||||
Opts.setDefaults();
|
Opts.setDefaults();
|
||||||
|
|
||||||
Opts.Backtrace = gwp_asan::options::getBacktraceFunction();
|
Opts.Backtrace = gwp_asan::backtrace::getBacktraceFunction();
|
||||||
Opts.InstallForkHandlers = gwp_asan::test::OnlyOnce();
|
Opts.InstallForkHandlers = gwp_asan::test::OnlyOnce();
|
||||||
GPA.init(Opts);
|
GPA.init(Opts);
|
||||||
|
|
||||||
gwp_asan::crash_handler::installSignalHandlers(
|
gwp_asan::segv_handler::installSignalHandlers(
|
||||||
&GPA, gwp_asan::test::getPrintfFunction(),
|
&GPA, gwp_asan::test::getPrintfFunction(),
|
||||||
gwp_asan::options::getPrintBacktraceFunction(),
|
gwp_asan::backtrace::getPrintBacktraceFunction(),
|
||||||
gwp_asan::crash_handler::getSegvBacktraceFunction());
|
gwp_asan::backtrace::getSegvBacktraceFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override {
|
void TearDown() override {
|
||||||
GPA.uninitTestOnly();
|
GPA.uninitTestOnly();
|
||||||
gwp_asan::crash_handler::uninstallSignalHandlers();
|
gwp_asan::segv_handler::uninstallSignalHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -6,15 +6,14 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "gwp_asan/optional/segv_handler.h"
|
#include "gwp_asan/optional/printf.h"
|
||||||
|
|
||||||
#include "sanitizer_common/sanitizer_common.h"
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
|
||||||
namespace gwp_asan {
|
namespace gwp_asan {
|
||||||
namespace test {
|
namespace test {
|
||||||
// This printf-function getter allows other platforms (e.g. Android) to define
|
|
||||||
// their own signal-safe Printf function. In LLVM, we use
|
Printf_t getPrintfFunction() { return __sanitizer::Printf; }
|
||||||
// `optional/printf_sanitizer_common.cpp` which supplies the __sanitizer::Printf
|
|
||||||
// for this purpose.
|
} // namespace test
|
||||||
crash_handler::Printf_t getPrintfFunction() { return __sanitizer::Printf; }
|
} // namespace gwp_asan
|
||||||
}; // namespace test
|
|
||||||
}; // namespace gwp_asan
|
|
|
@ -674,14 +674,14 @@ void initScudo() {
|
||||||
#ifdef GWP_ASAN_HOOKS
|
#ifdef GWP_ASAN_HOOKS
|
||||||
gwp_asan::options::initOptions();
|
gwp_asan::options::initOptions();
|
||||||
gwp_asan::options::Options &Opts = gwp_asan::options::getOptions();
|
gwp_asan::options::Options &Opts = gwp_asan::options::getOptions();
|
||||||
Opts.Backtrace = gwp_asan::options::getBacktraceFunction();
|
Opts.Backtrace = gwp_asan::backtrace::getBacktraceFunction();
|
||||||
GuardedAlloc.init(Opts);
|
GuardedAlloc.init(Opts);
|
||||||
|
|
||||||
if (Opts.InstallSignalHandlers)
|
if (Opts.InstallSignalHandlers)
|
||||||
gwp_asan::crash_handler::installSignalHandlers(
|
gwp_asan::segv_handler::installSignalHandlers(
|
||||||
&GuardedAlloc, __sanitizer::Printf,
|
&GuardedAlloc, __sanitizer::Printf,
|
||||||
gwp_asan::options::getPrintBacktraceFunction(),
|
gwp_asan::backtrace::getPrintBacktraceFunction(),
|
||||||
gwp_asan::crash_handler::getSegvBacktraceFunction());
|
gwp_asan::backtrace::getSegvBacktraceFunction());
|
||||||
#endif // GWP_ASAN_HOOKS
|
#endif // GWP_ASAN_HOOKS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -198,13 +198,14 @@ public:
|
||||||
// Allocator::disable calling GWPASan.disable). Disable GWP-ASan's atfork
|
// Allocator::disable calling GWPASan.disable). Disable GWP-ASan's atfork
|
||||||
// handler.
|
// handler.
|
||||||
Opt.InstallForkHandlers = false;
|
Opt.InstallForkHandlers = false;
|
||||||
Opt.Backtrace = gwp_asan::options::getBacktraceFunction();
|
Opt.Backtrace = gwp_asan::backtrace::getBacktraceFunction();
|
||||||
GuardedAlloc.init(Opt);
|
GuardedAlloc.init(Opt);
|
||||||
|
|
||||||
if (Opt.InstallSignalHandlers)
|
if (Opt.InstallSignalHandlers)
|
||||||
gwp_asan::crash_handler::installSignalHandlers(
|
gwp_asan::segv_handler::installSignalHandlers(
|
||||||
&GuardedAlloc, Printf, gwp_asan::options::getPrintBacktraceFunction(),
|
&GuardedAlloc, Printf,
|
||||||
gwp_asan::crash_handler::getSegvBacktraceFunction());
|
gwp_asan::backtrace::getPrintBacktraceFunction(),
|
||||||
|
gwp_asan::backtrace::getSegvBacktraceFunction());
|
||||||
#endif // GWP_ASAN_HOOKS
|
#endif // GWP_ASAN_HOOKS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +220,7 @@ public:
|
||||||
Primary.unmapTestOnly();
|
Primary.unmapTestOnly();
|
||||||
#ifdef GWP_ASAN_HOOKS
|
#ifdef GWP_ASAN_HOOKS
|
||||||
if (getFlags()->GWP_ASAN_InstallSignalHandlers)
|
if (getFlags()->GWP_ASAN_InstallSignalHandlers)
|
||||||
gwp_asan::crash_handler::uninstallSignalHandlers();
|
gwp_asan::segv_handler::uninstallSignalHandlers();
|
||||||
GuardedAlloc.uninitTestOnly();
|
GuardedAlloc.uninitTestOnly();
|
||||||
#endif // GWP_ASAN_HOOKS
|
#endif // GWP_ASAN_HOOKS
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue