[fuzzer] Add Windows Visual C++ exception intercept

Adds a new option, `handle_winexcept` to try to intercept uncaught
Visual C++ exceptions on Windows. On Linux, such exceptions are handled
implicitly by `std::terminate()` raising `SIBABRT`. This option brings the
Windows behavior in line with Linux.

Unfortunately this exception code is intentionally undocumented, however
has remained stable for the last decade. More information can be found
here: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273

Reviewed By: morehouse, metzman

Differential Revision: https://reviews.llvm.org/D89755
This commit is contained in:
Joe Pletcher 2020-11-12 12:37:35 -08:00 committed by Jonathan Metzman
parent 6c516cda39
commit f897e82bfd
6 changed files with 33 additions and 2 deletions

View File

@ -829,6 +829,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.HandleXfsz = Flags.handle_xfsz;
Options.HandleUsr1 = Flags.handle_usr1;
Options.HandleUsr2 = Flags.handle_usr2;
Options.HandleWinExcept = Flags.handle_winexcept;
SetSignalHandler(Options);
std::atexit(Fuzzer::StaticExitCallback);

View File

@ -145,6 +145,8 @@ FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
FUZZER_FLAG_INT(handle_winexcept, 1, "If 1, try to intercept uncaught Windows "
"Visual C++ Exceptions.")
FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
"if 2, close stderr; if 3, close both. "
"Be careful, this will also close e.g. stderr of asan.")

View File

@ -84,6 +84,7 @@ struct FuzzingOptions {
bool HandleXfsz = false;
bool HandleUsr1 = false;
bool HandleUsr2 = false;
bool HandleWinExcept = false;
};
} // namespace fuzzer

View File

@ -60,7 +60,15 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
if (HandlerOpt->HandleFpe)
Fuzzer::StaticCrashSignalCallback();
break;
// TODO: handle (Options.HandleXfsz)
// This is an undocumented exception code corresponding to a Visual C++
// Exception.
//
// See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
case 0xE06D7363:
if (HandlerOpt->HandleWinExcept)
Fuzzer::StaticCrashSignalCallback();
break;
// TODO: Handle (Options.HandleXfsz)
}
return EXCEPTION_CONTINUE_SEARCH;
}
@ -127,7 +135,7 @@ void SetSignalHandler(const FuzzingOptions& Options) {
}
if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
Options.HandleFpe)
Options.HandleFpe || Options.HandleWinExcept)
SetUnhandledExceptionFilter(ExceptionHandler);
if (Options.HandleAbrt)

View File

@ -0,0 +1,10 @@
#include <cstdint>
#include <vector>
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, size_t size) {
std::vector<uint8_t> v;
// Intentionally throw std::length_error
v.reserve(static_cast<uint64_t>(-1));
return 0;
}

View File

@ -0,0 +1,8 @@
# Test that throws a C++ exception and doesn't catch it. Should result in a
# crash
RUN: %cpp_compiler %S/UncaughtException.cpp -o %t-UncaughtException
RUN: not %run %t-UncaughtException 2>&1 | FileCheck %s
CHECK: ERROR: libFuzzer: deadly signal
CHECK: Test unit written to ./crash