llvm-project/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
Aaron Green c4a41cd77c Refactor mutation strategies into a standalone library
This change introduces libMutagen/libclang_rt.mutagen.a as a subset of libFuzzer/libclang_rt.fuzzer.a. This library contains only the fuzzing strategies used by libFuzzer to produce new test inputs from provided inputs, dictionaries, and SanitizerCoverage feedback.

Most of this change is simply moving sections of code to one side or the other of the library boundary. The only meaningful new code is:

* The Mutagen.h interface and its implementation in Mutagen.cpp.
* The following methods in MutagenDispatcher.cpp:
  * UseCmp
  * UseMemmem
  * SetCustomMutator
  * SetCustomCrossOver
  * LateInitialize (similar to the MutationDispatcher's original constructor)
  * Mutate_AddWordFromTORC (uses callbacks instead of accessing TPC directly)
  * StartMutationSequence
  * MutationSequence
  * DictionaryEntrySequence
  * RecommendDictionary
  * RecommendDictionaryEntry
* FuzzerMutate.cpp (which now justs sets callbacks and handles printing)
* MutagenUnittest.cpp (which adds tests of Mutagen.h)

A note on performance: This change was tested with a 100 passes of test/fuzzer/LargeTest.cpp with 1000 runs per pass, both with and without the change. The running time distribution was qualitatively similar both with and without the change, and the average difference was within 30 microseconds (2.240 ms/run vs 2.212 ms/run, respectively). Both times were much higher than observed with the fully optimized system clang (~0.38 ms/run), most likely due to the combination of CMake "dev mode" settings (e.g. CMAKE_BUILD_TYPE="Debug", LLVM_ENABLE_LTO=OFF, etc.). The difference between the two versions built similarly seems to be "in the noise" and suggests no meaningful performance degradation.

Reviewed By: morehouse

Differential Revision: https://reviews.llvm.org/D102447
2021-05-26 13:27:49 -07:00

209 lines
5.7 KiB
C++

//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// Misc utils implementation for Windows.
//===----------------------------------------------------------------------===//
#include "FuzzerPlatform.h"
#if LIBFUZZER_WINDOWS
#include "FuzzerCommand.h"
#include "FuzzerIO.h"
#include "FuzzerInternal.h"
#include <cassert>
#include <chrono>
#include <cstring>
#include <errno.h>
#include <io.h>
#include <iomanip>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <windows.h>
// This must be included after windows.h.
#include <psapi.h>
namespace fuzzer {
static const FuzzingOptions* HandlerOpt = nullptr;
static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_STACK_OVERFLOW:
if (HandlerOpt->HandleSegv)
Fuzzer::StaticCrashSignalCallback();
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_IN_PAGE_ERROR:
if (HandlerOpt->HandleBus)
Fuzzer::StaticCrashSignalCallback();
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_PRIV_INSTRUCTION:
if (HandlerOpt->HandleIll)
Fuzzer::StaticCrashSignalCallback();
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
if (HandlerOpt->HandleFpe)
Fuzzer::StaticCrashSignalCallback();
break;
// 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;
}
BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
switch (dwCtrlType) {
case CTRL_C_EVENT:
if (HandlerOpt->HandleInt)
Fuzzer::StaticInterruptCallback();
return TRUE;
case CTRL_BREAK_EVENT:
if (HandlerOpt->HandleTerm)
Fuzzer::StaticInterruptCallback();
return TRUE;
}
return FALSE;
}
void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
Fuzzer::StaticAlarmCallback();
}
class TimerQ {
HANDLE TimerQueue;
public:
TimerQ() : TimerQueue(NULL) {}
~TimerQ() {
if (TimerQueue)
DeleteTimerQueueEx(TimerQueue, NULL);
}
void SetTimer(int Seconds) {
if (!TimerQueue) {
TimerQueue = CreateTimerQueue();
if (!TimerQueue) {
Printf("libFuzzer: CreateTimerQueue failed.\n");
exit(1);
}
}
HANDLE Timer;
if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
Seconds*1000, Seconds*1000, 0)) {
Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
exit(1);
}
}
};
static TimerQ Timer;
static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
void SetSignalHandler(const FuzzingOptions& Options) {
HandlerOpt = &Options;
if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
if (Options.HandleInt || Options.HandleTerm)
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
DWORD LastError = GetLastError();
Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
LastError);
exit(1);
}
if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
Options.HandleFpe || Options.HandleWinExcept)
SetUnhandledExceptionFilter(ExceptionHandler);
if (Options.HandleAbrt)
if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
Printf("libFuzzer: signal failed with %d\n", errno);
exit(1);
}
}
void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
unsigned long GetPid() { return GetCurrentProcessId(); }
size_t GetPeakRSSMb() {
PROCESS_MEMORY_COUNTERS info;
if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
return 0;
return info.PeakWorkingSetSize >> 20;
}
FILE *OpenProcessPipe(const char *Command, const char *Mode) {
return _popen(Command, Mode);
}
int CloseProcessPipe(FILE *F) {
return _pclose(F);
}
int ExecuteCommand(const Command &Cmd) {
std::string CmdLine = Cmd.toString();
return system(CmdLine.c_str());
}
bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
if (!Pipe)
return false;
if (CmdOutput) {
char TmpBuffer[128];
while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
CmdOutput->append(TmpBuffer);
}
return _pclose(Pipe) == 0;
}
std::string DisassembleCmd(const std::string &FileName) {
Vector<std::string> command_vector;
command_vector.push_back("dumpbin /summary > nul");
if (ExecuteCommand(Command(command_vector)) == 0)
return "dumpbin /disasm " + FileName;
Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
exit(1);
}
std::string SearchRegexCmd(const std::string &Regex) {
return "findstr /r \"" + Regex + "\"";
}
void DiscardOutput(int Fd) {
FILE* Temp = fopen("nul", "w");
if (!Temp)
return;
_dup2(_fileno(Temp), Fd);
fclose(Temp);
}
} // namespace fuzzer
#endif // LIBFUZZER_WINDOWS