10b57cec5SDimitry Andric //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // Misc utils implementation for Windows.
90b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
105ffd83dbSDimitry Andric #include "FuzzerPlatform.h"
110b57cec5SDimitry Andric #if LIBFUZZER_WINDOWS
120b57cec5SDimitry Andric #include "FuzzerCommand.h"
130b57cec5SDimitry Andric #include "FuzzerIO.h"
140b57cec5SDimitry Andric #include "FuzzerInternal.h"
150b57cec5SDimitry Andric #include <cassert>
160b57cec5SDimitry Andric #include <chrono>
170b57cec5SDimitry Andric #include <cstring>
180b57cec5SDimitry Andric #include <errno.h>
19480093f4SDimitry Andric #include <io.h>
200b57cec5SDimitry Andric #include <iomanip>
210b57cec5SDimitry Andric #include <signal.h>
220b57cec5SDimitry Andric #include <stdio.h>
230b57cec5SDimitry Andric #include <sys/types.h>
240b57cec5SDimitry Andric #include <windows.h>
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric // This must be included after windows.h.
270b57cec5SDimitry Andric #include <psapi.h>
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric namespace fuzzer {
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr;
320b57cec5SDimitry Andric
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)330b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
340b57cec5SDimitry Andric switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
350b57cec5SDimitry Andric case EXCEPTION_ACCESS_VIOLATION:
360b57cec5SDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
370b57cec5SDimitry Andric case EXCEPTION_STACK_OVERFLOW:
380b57cec5SDimitry Andric if (HandlerOpt->HandleSegv)
390b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback();
400b57cec5SDimitry Andric break;
410b57cec5SDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT:
420b57cec5SDimitry Andric case EXCEPTION_IN_PAGE_ERROR:
430b57cec5SDimitry Andric if (HandlerOpt->HandleBus)
440b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback();
450b57cec5SDimitry Andric break;
460b57cec5SDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION:
470b57cec5SDimitry Andric case EXCEPTION_PRIV_INSTRUCTION:
480b57cec5SDimitry Andric if (HandlerOpt->HandleIll)
490b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback();
500b57cec5SDimitry Andric break;
510b57cec5SDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND:
520b57cec5SDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO:
530b57cec5SDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT:
540b57cec5SDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION:
550b57cec5SDimitry Andric case EXCEPTION_FLT_OVERFLOW:
560b57cec5SDimitry Andric case EXCEPTION_FLT_STACK_CHECK:
570b57cec5SDimitry Andric case EXCEPTION_FLT_UNDERFLOW:
580b57cec5SDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO:
590b57cec5SDimitry Andric case EXCEPTION_INT_OVERFLOW:
600b57cec5SDimitry Andric if (HandlerOpt->HandleFpe)
610b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback();
620b57cec5SDimitry Andric break;
63e8d8bef9SDimitry Andric // This is an undocumented exception code corresponding to a Visual C++
64e8d8bef9SDimitry Andric // Exception.
65e8d8bef9SDimitry Andric //
66e8d8bef9SDimitry Andric // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
67e8d8bef9SDimitry Andric case 0xE06D7363:
68e8d8bef9SDimitry Andric if (HandlerOpt->HandleWinExcept)
69e8d8bef9SDimitry Andric Fuzzer::StaticCrashSignalCallback();
70e8d8bef9SDimitry Andric break;
71e8d8bef9SDimitry Andric // TODO: Handle (Options.HandleXfsz)
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric return EXCEPTION_CONTINUE_SEARCH;
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
CtrlHandler(DWORD dwCtrlType)760b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
770b57cec5SDimitry Andric switch (dwCtrlType) {
780b57cec5SDimitry Andric case CTRL_C_EVENT:
790b57cec5SDimitry Andric if (HandlerOpt->HandleInt)
800b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback();
810b57cec5SDimitry Andric return TRUE;
820b57cec5SDimitry Andric case CTRL_BREAK_EVENT:
830b57cec5SDimitry Andric if (HandlerOpt->HandleTerm)
840b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback();
850b57cec5SDimitry Andric return TRUE;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric return FALSE;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric
AlarmHandler(PVOID,BOOLEAN)900b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
910b57cec5SDimitry Andric Fuzzer::StaticAlarmCallback();
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric class TimerQ {
950b57cec5SDimitry Andric HANDLE TimerQueue;
960b57cec5SDimitry Andric public:
TimerQ()970b57cec5SDimitry Andric TimerQ() : TimerQueue(NULL) {}
~TimerQ()980b57cec5SDimitry Andric ~TimerQ() {
990b57cec5SDimitry Andric if (TimerQueue)
1000b57cec5SDimitry Andric DeleteTimerQueueEx(TimerQueue, NULL);
1010b57cec5SDimitry Andric }
SetTimer(int Seconds)1020b57cec5SDimitry Andric void SetTimer(int Seconds) {
1030b57cec5SDimitry Andric if (!TimerQueue) {
1040b57cec5SDimitry Andric TimerQueue = CreateTimerQueue();
1050b57cec5SDimitry Andric if (!TimerQueue) {
1060b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueue failed.\n");
1070b57cec5SDimitry Andric exit(1);
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric HANDLE Timer;
1110b57cec5SDimitry Andric if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
1120b57cec5SDimitry Andric Seconds*1000, Seconds*1000, 0)) {
1130b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
1140b57cec5SDimitry Andric exit(1);
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric };
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric static TimerQ Timer;
1200b57cec5SDimitry Andric
CrashHandler(int)1210b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
1220b57cec5SDimitry Andric
SetSignalHandler(const FuzzingOptions & Options)1230b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) {
1240b57cec5SDimitry Andric HandlerOpt = &Options;
1250b57cec5SDimitry Andric
126e8d8bef9SDimitry Andric if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
1270b57cec5SDimitry Andric Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric if (Options.HandleInt || Options.HandleTerm)
1300b57cec5SDimitry Andric if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
1310b57cec5SDimitry Andric DWORD LastError = GetLastError();
1320b57cec5SDimitry Andric Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
1330b57cec5SDimitry Andric LastError);
1340b57cec5SDimitry Andric exit(1);
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric
1370b57cec5SDimitry Andric if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
138e8d8bef9SDimitry Andric Options.HandleFpe || Options.HandleWinExcept)
1390b57cec5SDimitry Andric SetUnhandledExceptionFilter(ExceptionHandler);
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric if (Options.HandleAbrt)
1420b57cec5SDimitry Andric if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
1430b57cec5SDimitry Andric Printf("libFuzzer: signal failed with %d\n", errno);
1440b57cec5SDimitry Andric exit(1);
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric
SleepSeconds(int Seconds)1480b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
1490b57cec5SDimitry Andric
GetPid()1500b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); }
1510b57cec5SDimitry Andric
GetPeakRSSMb()1520b57cec5SDimitry Andric size_t GetPeakRSSMb() {
1530b57cec5SDimitry Andric PROCESS_MEMORY_COUNTERS info;
1540b57cec5SDimitry Andric if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
1550b57cec5SDimitry Andric return 0;
1560b57cec5SDimitry Andric return info.PeakWorkingSetSize >> 20;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
OpenProcessPipe(const char * Command,const char * Mode)1590b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) {
1600b57cec5SDimitry Andric return _popen(Command, Mode);
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric
CloseProcessPipe(FILE * F)1635ffd83dbSDimitry Andric int CloseProcessPipe(FILE *F) {
1645ffd83dbSDimitry Andric return _pclose(F);
1655ffd83dbSDimitry Andric }
1665ffd83dbSDimitry Andric
ExecuteCommand(const Command & Cmd)1670b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) {
1680b57cec5SDimitry Andric std::string CmdLine = Cmd.toString();
1690b57cec5SDimitry Andric return system(CmdLine.c_str());
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
ExecuteCommand(const Command & Cmd,std::string * CmdOutput)1725ffd83dbSDimitry Andric bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
1735ffd83dbSDimitry Andric FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
1745ffd83dbSDimitry Andric if (!Pipe)
1755ffd83dbSDimitry Andric return false;
1765ffd83dbSDimitry Andric
1775ffd83dbSDimitry Andric if (CmdOutput) {
1785ffd83dbSDimitry Andric char TmpBuffer[128];
1795ffd83dbSDimitry Andric while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
1805ffd83dbSDimitry Andric CmdOutput->append(TmpBuffer);
1815ffd83dbSDimitry Andric }
1825ffd83dbSDimitry Andric return _pclose(Pipe) == 0;
1835ffd83dbSDimitry Andric }
1845ffd83dbSDimitry Andric
SearchMemory(const void * Data,size_t DataLen,const void * Patt,size_t PattLen)1850b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
1860b57cec5SDimitry Andric size_t PattLen) {
1870b57cec5SDimitry Andric // TODO: make this implementation more efficient.
1880b57cec5SDimitry Andric const char *Cdata = (const char *)Data;
1890b57cec5SDimitry Andric const char *Cpatt = (const char *)Patt;
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
1920b57cec5SDimitry Andric return NULL;
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric if (PattLen == 1)
1950b57cec5SDimitry Andric return memchr(Data, *Cpatt, DataLen);
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric const char *End = Cdata + DataLen - PattLen + 1;
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric for (const char *It = Cdata; It < End; ++It)
2000b57cec5SDimitry Andric if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
2010b57cec5SDimitry Andric return It;
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric return NULL;
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric
DisassembleCmd(const std::string & FileName)2060b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) {
207349cc55cSDimitry Andric std::vector<std::string> command_vector;
2080b57cec5SDimitry Andric command_vector.push_back("dumpbin /summary > nul");
2090b57cec5SDimitry Andric if (ExecuteCommand(Command(command_vector)) == 0)
2100b57cec5SDimitry Andric return "dumpbin /disasm " + FileName;
2110b57cec5SDimitry Andric Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
2120b57cec5SDimitry Andric exit(1);
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric
SearchRegexCmd(const std::string & Regex)2150b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) {
2160b57cec5SDimitry Andric return "findstr /r \"" + Regex + "\"";
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
DiscardOutput(int Fd)219480093f4SDimitry Andric void DiscardOutput(int Fd) {
220480093f4SDimitry Andric FILE* Temp = fopen("nul", "w");
221480093f4SDimitry Andric if (!Temp)
222480093f4SDimitry Andric return;
223480093f4SDimitry Andric _dup2(_fileno(Temp), Fd);
224480093f4SDimitry Andric fclose(Temp);
225480093f4SDimitry Andric }
226480093f4SDimitry Andric
PageSize()22706c3fb27SDimitry Andric size_t PageSize() {
22806c3fb27SDimitry Andric static size_t PageSizeCached = []() -> size_t {
22906c3fb27SDimitry Andric SYSTEM_INFO si;
23006c3fb27SDimitry Andric GetSystemInfo(&si);
23106c3fb27SDimitry Andric return si.dwPageSize;
23206c3fb27SDimitry Andric }();
23306c3fb27SDimitry Andric return PageSizeCached;
23406c3fb27SDimitry Andric }
23506c3fb27SDimitry Andric
SetThreadName(std::thread & thread,const std::string & name)2365f757f3fSDimitry Andric void SetThreadName(std::thread &thread, const std::string &name) {
2375f757f3fSDimitry Andric // TODO ?
2385f757f3fSDimitry Andric // to UTF-8 then SetThreadDescription ?
2395f757f3fSDimitry Andric }
2405f757f3fSDimitry Andric
2410b57cec5SDimitry Andric } // namespace fuzzer
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS
244