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 //===----------------------------------------------------------------------===// 100b57cec5SDimitry Andric #include "FuzzerDefs.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> 19*480093f4SDimitry 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 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; 630b57cec5SDimitry Andric // TODO: handle (Options.HandleXfsz) 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { 690b57cec5SDimitry Andric switch (dwCtrlType) { 700b57cec5SDimitry Andric case CTRL_C_EVENT: 710b57cec5SDimitry Andric if (HandlerOpt->HandleInt) 720b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback(); 730b57cec5SDimitry Andric return TRUE; 740b57cec5SDimitry Andric case CTRL_BREAK_EVENT: 750b57cec5SDimitry Andric if (HandlerOpt->HandleTerm) 760b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback(); 770b57cec5SDimitry Andric return TRUE; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric return FALSE; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) { 830b57cec5SDimitry Andric Fuzzer::StaticAlarmCallback(); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric class TimerQ { 870b57cec5SDimitry Andric HANDLE TimerQueue; 880b57cec5SDimitry Andric public: 890b57cec5SDimitry Andric TimerQ() : TimerQueue(NULL) {} 900b57cec5SDimitry Andric ~TimerQ() { 910b57cec5SDimitry Andric if (TimerQueue) 920b57cec5SDimitry Andric DeleteTimerQueueEx(TimerQueue, NULL); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric void SetTimer(int Seconds) { 950b57cec5SDimitry Andric if (!TimerQueue) { 960b57cec5SDimitry Andric TimerQueue = CreateTimerQueue(); 970b57cec5SDimitry Andric if (!TimerQueue) { 980b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueue failed.\n"); 990b57cec5SDimitry Andric exit(1); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric HANDLE Timer; 1030b57cec5SDimitry Andric if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, 1040b57cec5SDimitry Andric Seconds*1000, Seconds*1000, 0)) { 1050b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); 1060b57cec5SDimitry Andric exit(1); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric }; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric static TimerQ Timer; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) { 1160b57cec5SDimitry Andric HandlerOpt = &Options; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric if (Options.UnitTimeoutSec > 0) 1190b57cec5SDimitry Andric Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric if (Options.HandleInt || Options.HandleTerm) 1220b57cec5SDimitry Andric if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { 1230b57cec5SDimitry Andric DWORD LastError = GetLastError(); 1240b57cec5SDimitry Andric Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", 1250b57cec5SDimitry Andric LastError); 1260b57cec5SDimitry Andric exit(1); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || 1300b57cec5SDimitry Andric Options.HandleFpe) 1310b57cec5SDimitry Andric SetUnhandledExceptionFilter(ExceptionHandler); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric if (Options.HandleAbrt) 1340b57cec5SDimitry Andric if (SIG_ERR == signal(SIGABRT, CrashHandler)) { 1350b57cec5SDimitry Andric Printf("libFuzzer: signal failed with %d\n", errno); 1360b57cec5SDimitry Andric exit(1); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric size_t GetPeakRSSMb() { 1450b57cec5SDimitry Andric PROCESS_MEMORY_COUNTERS info; 1460b57cec5SDimitry Andric if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) 1470b57cec5SDimitry Andric return 0; 1480b57cec5SDimitry Andric return info.PeakWorkingSetSize >> 20; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) { 1520b57cec5SDimitry Andric return _popen(Command, Mode); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) { 1560b57cec5SDimitry Andric std::string CmdLine = Cmd.toString(); 1570b57cec5SDimitry Andric return system(CmdLine.c_str()); 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 1610b57cec5SDimitry Andric size_t PattLen) { 1620b57cec5SDimitry Andric // TODO: make this implementation more efficient. 1630b57cec5SDimitry Andric const char *Cdata = (const char *)Data; 1640b57cec5SDimitry Andric const char *Cpatt = (const char *)Patt; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) 1670b57cec5SDimitry Andric return NULL; 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric if (PattLen == 1) 1700b57cec5SDimitry Andric return memchr(Data, *Cpatt, DataLen); 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric const char *End = Cdata + DataLen - PattLen + 1; 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric for (const char *It = Cdata; It < End; ++It) 1750b57cec5SDimitry Andric if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) 1760b57cec5SDimitry Andric return It; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric return NULL; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) { 1820b57cec5SDimitry Andric Vector<std::string> command_vector; 1830b57cec5SDimitry Andric command_vector.push_back("dumpbin /summary > nul"); 1840b57cec5SDimitry Andric if (ExecuteCommand(Command(command_vector)) == 0) 1850b57cec5SDimitry Andric return "dumpbin /disasm " + FileName; 1860b57cec5SDimitry Andric Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); 1870b57cec5SDimitry Andric exit(1); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) { 1910b57cec5SDimitry Andric return "findstr /r \"" + Regex + "\""; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 194*480093f4SDimitry Andric void DiscardOutput(int Fd) { 195*480093f4SDimitry Andric FILE* Temp = fopen("nul", "w"); 196*480093f4SDimitry Andric if (!Temp) 197*480093f4SDimitry Andric return; 198*480093f4SDimitry Andric _dup2(_fileno(Temp), Fd); 199*480093f4SDimitry Andric fclose(Temp); 200*480093f4SDimitry Andric } 201*480093f4SDimitry Andric 2020b57cec5SDimitry Andric } // namespace fuzzer 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS 205