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