110ab2aceSGeorge Karpenkov //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // Misc utils implementation for Windows.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
10226866e1SDokyung Song #include "FuzzerPlatform.h"
1110ab2aceSGeorge Karpenkov #if LIBFUZZER_WINDOWS
1204304d12SMatt Morehouse #include "FuzzerCommand.h"
1310ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
1510ab2aceSGeorge Karpenkov #include <cassert>
1610ab2aceSGeorge Karpenkov #include <chrono>
1710ab2aceSGeorge Karpenkov #include <cstring>
1810ab2aceSGeorge Karpenkov #include <errno.h>
19e5b603a4SMarco Vanotti #include <io.h>
2010ab2aceSGeorge Karpenkov #include <iomanip>
2110ab2aceSGeorge Karpenkov #include <signal.h>
2210ab2aceSGeorge Karpenkov #include <stdio.h>
2310ab2aceSGeorge Karpenkov #include <sys/types.h>
2410ab2aceSGeorge Karpenkov #include <windows.h>
2510ab2aceSGeorge Karpenkov 
2610ab2aceSGeorge Karpenkov // This must be included after windows.h.
27e199a2d4SMartin Storsjo #include <psapi.h>
2810ab2aceSGeorge Karpenkov 
2910ab2aceSGeorge Karpenkov namespace fuzzer {
3010ab2aceSGeorge Karpenkov 
3110ab2aceSGeorge Karpenkov static const FuzzingOptions* HandlerOpt = nullptr;
3210ab2aceSGeorge Karpenkov 
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)3310ab2aceSGeorge Karpenkov static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
3410ab2aceSGeorge Karpenkov   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
3510ab2aceSGeorge Karpenkov     case EXCEPTION_ACCESS_VIOLATION:
3610ab2aceSGeorge Karpenkov     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
3710ab2aceSGeorge Karpenkov     case EXCEPTION_STACK_OVERFLOW:
3810ab2aceSGeorge Karpenkov       if (HandlerOpt->HandleSegv)
3910ab2aceSGeorge Karpenkov         Fuzzer::StaticCrashSignalCallback();
4010ab2aceSGeorge Karpenkov       break;
4110ab2aceSGeorge Karpenkov     case EXCEPTION_DATATYPE_MISALIGNMENT:
4210ab2aceSGeorge Karpenkov     case EXCEPTION_IN_PAGE_ERROR:
4310ab2aceSGeorge Karpenkov       if (HandlerOpt->HandleBus)
4410ab2aceSGeorge Karpenkov         Fuzzer::StaticCrashSignalCallback();
4510ab2aceSGeorge Karpenkov       break;
4610ab2aceSGeorge Karpenkov     case EXCEPTION_ILLEGAL_INSTRUCTION:
4710ab2aceSGeorge Karpenkov     case EXCEPTION_PRIV_INSTRUCTION:
4810ab2aceSGeorge Karpenkov       if (HandlerOpt->HandleIll)
4910ab2aceSGeorge Karpenkov         Fuzzer::StaticCrashSignalCallback();
5010ab2aceSGeorge Karpenkov       break;
5110ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_DENORMAL_OPERAND:
5210ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
5310ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_INEXACT_RESULT:
5410ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_INVALID_OPERATION:
5510ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_OVERFLOW:
5610ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_STACK_CHECK:
5710ab2aceSGeorge Karpenkov     case EXCEPTION_FLT_UNDERFLOW:
5810ab2aceSGeorge Karpenkov     case EXCEPTION_INT_DIVIDE_BY_ZERO:
5910ab2aceSGeorge Karpenkov     case EXCEPTION_INT_OVERFLOW:
6010ab2aceSGeorge Karpenkov       if (HandlerOpt->HandleFpe)
6110ab2aceSGeorge Karpenkov         Fuzzer::StaticCrashSignalCallback();
6210ab2aceSGeorge Karpenkov       break;
63f897e82bSJoe Pletcher     // This is an undocumented exception code corresponding to a Visual C++
64f897e82bSJoe Pletcher     // Exception.
65f897e82bSJoe Pletcher     //
66f897e82bSJoe Pletcher     // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
67f897e82bSJoe Pletcher     case 0xE06D7363:
68f897e82bSJoe Pletcher       if (HandlerOpt->HandleWinExcept)
69f897e82bSJoe Pletcher         Fuzzer::StaticCrashSignalCallback();
70f897e82bSJoe Pletcher       break;
71f897e82bSJoe Pletcher       // TODO: Handle (Options.HandleXfsz)
7210ab2aceSGeorge Karpenkov   }
7310ab2aceSGeorge Karpenkov   return EXCEPTION_CONTINUE_SEARCH;
7410ab2aceSGeorge Karpenkov }
7510ab2aceSGeorge Karpenkov 
CtrlHandler(DWORD dwCtrlType)7610ab2aceSGeorge Karpenkov BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
7710ab2aceSGeorge Karpenkov   switch (dwCtrlType) {
7810ab2aceSGeorge Karpenkov     case CTRL_C_EVENT:
7910ab2aceSGeorge Karpenkov       if (HandlerOpt->HandleInt)
8010ab2aceSGeorge Karpenkov         Fuzzer::StaticInterruptCallback();
8110ab2aceSGeorge Karpenkov       return TRUE;
8210ab2aceSGeorge Karpenkov     case CTRL_BREAK_EVENT:
8310ab2aceSGeorge Karpenkov       if (HandlerOpt->HandleTerm)
8410ab2aceSGeorge Karpenkov         Fuzzer::StaticInterruptCallback();
8510ab2aceSGeorge Karpenkov       return TRUE;
8610ab2aceSGeorge Karpenkov   }
8710ab2aceSGeorge Karpenkov   return FALSE;
8810ab2aceSGeorge Karpenkov }
8910ab2aceSGeorge Karpenkov 
AlarmHandler(PVOID,BOOLEAN)9010ab2aceSGeorge Karpenkov void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
9110ab2aceSGeorge Karpenkov   Fuzzer::StaticAlarmCallback();
9210ab2aceSGeorge Karpenkov }
9310ab2aceSGeorge Karpenkov 
9410ab2aceSGeorge Karpenkov class TimerQ {
9510ab2aceSGeorge Karpenkov   HANDLE TimerQueue;
9610ab2aceSGeorge Karpenkov  public:
TimerQ()977821f892SJonathan Metzman   TimerQ() : TimerQueue(NULL) {}
~TimerQ()9810ab2aceSGeorge Karpenkov   ~TimerQ() {
9910ab2aceSGeorge Karpenkov     if (TimerQueue)
10010ab2aceSGeorge Karpenkov       DeleteTimerQueueEx(TimerQueue, NULL);
1017821f892SJonathan Metzman   }
SetTimer(int Seconds)10210ab2aceSGeorge Karpenkov   void SetTimer(int Seconds) {
10310ab2aceSGeorge Karpenkov     if (!TimerQueue) {
10410ab2aceSGeorge Karpenkov       TimerQueue = CreateTimerQueue();
10510ab2aceSGeorge Karpenkov       if (!TimerQueue) {
10610ab2aceSGeorge Karpenkov         Printf("libFuzzer: CreateTimerQueue failed.\n");
10710ab2aceSGeorge Karpenkov         exit(1);
10810ab2aceSGeorge Karpenkov       }
10910ab2aceSGeorge Karpenkov     }
11010ab2aceSGeorge Karpenkov     HANDLE Timer;
11110ab2aceSGeorge Karpenkov     if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
11210ab2aceSGeorge Karpenkov         Seconds*1000, Seconds*1000, 0)) {
11310ab2aceSGeorge Karpenkov       Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
11410ab2aceSGeorge Karpenkov       exit(1);
11510ab2aceSGeorge Karpenkov     }
1167821f892SJonathan Metzman   }
11710ab2aceSGeorge Karpenkov };
11810ab2aceSGeorge Karpenkov 
11910ab2aceSGeorge Karpenkov static TimerQ Timer;
12010ab2aceSGeorge Karpenkov 
CrashHandler(int)12110ab2aceSGeorge Karpenkov static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
12210ab2aceSGeorge Karpenkov 
SetSignalHandler(const FuzzingOptions & Options)12310ab2aceSGeorge Karpenkov void SetSignalHandler(const FuzzingOptions& Options) {
12410ab2aceSGeorge Karpenkov   HandlerOpt = &Options;
12510ab2aceSGeorge Karpenkov 
1269df7ee34SIlya Leoshkevich   if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
12710ab2aceSGeorge Karpenkov     Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
12810ab2aceSGeorge Karpenkov 
12910ab2aceSGeorge Karpenkov   if (Options.HandleInt || Options.HandleTerm)
13010ab2aceSGeorge Karpenkov     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
13110ab2aceSGeorge Karpenkov       DWORD LastError = GetLastError();
13210ab2aceSGeorge Karpenkov       Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
13310ab2aceSGeorge Karpenkov         LastError);
13410ab2aceSGeorge Karpenkov       exit(1);
13510ab2aceSGeorge Karpenkov     }
13610ab2aceSGeorge Karpenkov 
13710ab2aceSGeorge Karpenkov   if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
138f897e82bSJoe Pletcher       Options.HandleFpe || Options.HandleWinExcept)
13910ab2aceSGeorge Karpenkov     SetUnhandledExceptionFilter(ExceptionHandler);
14010ab2aceSGeorge Karpenkov 
14110ab2aceSGeorge Karpenkov   if (Options.HandleAbrt)
14210ab2aceSGeorge Karpenkov     if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
14310ab2aceSGeorge Karpenkov       Printf("libFuzzer: signal failed with %d\n", errno);
14410ab2aceSGeorge Karpenkov       exit(1);
14510ab2aceSGeorge Karpenkov     }
14610ab2aceSGeorge Karpenkov }
14710ab2aceSGeorge Karpenkov 
SleepSeconds(int Seconds)14810ab2aceSGeorge Karpenkov void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
14910ab2aceSGeorge Karpenkov 
GetPid()15010ab2aceSGeorge Karpenkov unsigned long GetPid() { return GetCurrentProcessId(); }
15110ab2aceSGeorge Karpenkov 
GetPeakRSSMb()15210ab2aceSGeorge Karpenkov size_t GetPeakRSSMb() {
15310ab2aceSGeorge Karpenkov   PROCESS_MEMORY_COUNTERS info;
15410ab2aceSGeorge Karpenkov   if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
15510ab2aceSGeorge Karpenkov     return 0;
15610ab2aceSGeorge Karpenkov   return info.PeakWorkingSetSize >> 20;
15710ab2aceSGeorge Karpenkov }
15810ab2aceSGeorge Karpenkov 
OpenProcessPipe(const char * Command,const char * Mode)15910ab2aceSGeorge Karpenkov FILE *OpenProcessPipe(const char *Command, const char *Mode) {
16010ab2aceSGeorge Karpenkov   return _popen(Command, Mode);
16110ab2aceSGeorge Karpenkov }
16210ab2aceSGeorge Karpenkov 
CloseProcessPipe(FILE * F)16385515c7fSYuanfang Chen int CloseProcessPipe(FILE *F) {
16485515c7fSYuanfang Chen   return _pclose(F);
16585515c7fSYuanfang Chen }
16685515c7fSYuanfang Chen 
ExecuteCommand(const Command & Cmd)16704304d12SMatt Morehouse int ExecuteCommand(const Command &Cmd) {
16804304d12SMatt Morehouse   std::string CmdLine = Cmd.toString();
16904304d12SMatt Morehouse   return system(CmdLine.c_str());
17010ab2aceSGeorge Karpenkov }
17110ab2aceSGeorge Karpenkov 
ExecuteCommand(const Command & Cmd,std::string * CmdOutput)1724caeb62eSYuanfang Chen bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
1734caeb62eSYuanfang Chen   FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
1744caeb62eSYuanfang Chen   if (!Pipe)
1754caeb62eSYuanfang Chen     return false;
1764caeb62eSYuanfang Chen 
1774caeb62eSYuanfang Chen   if (CmdOutput) {
1784caeb62eSYuanfang Chen     char TmpBuffer[128];
1794caeb62eSYuanfang Chen     while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
1804caeb62eSYuanfang Chen       CmdOutput->append(TmpBuffer);
1814caeb62eSYuanfang Chen   }
1824caeb62eSYuanfang Chen   return _pclose(Pipe) == 0;
1834caeb62eSYuanfang Chen }
1844caeb62eSYuanfang Chen 
SearchMemory(const void * Data,size_t DataLen,const void * Patt,size_t PattLen)185c5d72517SMarco Vanotti const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
186c5d72517SMarco Vanotti                          size_t PattLen) {
187c5d72517SMarco Vanotti   // TODO: make this implementation more efficient.
188c5d72517SMarco Vanotti   const char *Cdata = (const char *)Data;
189c5d72517SMarco Vanotti   const char *Cpatt = (const char *)Patt;
190c5d72517SMarco Vanotti 
191c5d72517SMarco Vanotti   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
192c5d72517SMarco Vanotti     return NULL;
193c5d72517SMarco Vanotti 
194c5d72517SMarco Vanotti   if (PattLen == 1)
195c5d72517SMarco Vanotti     return memchr(Data, *Cpatt, DataLen);
196c5d72517SMarco Vanotti 
197c5d72517SMarco Vanotti   const char *End = Cdata + DataLen - PattLen + 1;
198c5d72517SMarco Vanotti 
199c5d72517SMarco Vanotti   for (const char *It = Cdata; It < End; ++It)
200c5d72517SMarco Vanotti     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
201c5d72517SMarco Vanotti       return It;
202c5d72517SMarco Vanotti 
203c5d72517SMarco Vanotti   return NULL;
204c5d72517SMarco Vanotti }
205c5d72517SMarco Vanotti 
DisassembleCmd(const std::string & FileName)20610ab2aceSGeorge Karpenkov std::string DisassembleCmd(const std::string &FileName) {
207*7c921753SKostya Serebryany   std::vector<std::string> command_vector;
2087e042bb1SMatt Morehouse   command_vector.push_back("dumpbin /summary > nul");
2097e042bb1SMatt Morehouse   if (ExecuteCommand(Command(command_vector)) == 0)
21010ab2aceSGeorge Karpenkov     return "dumpbin /disasm " + FileName;
21110ab2aceSGeorge Karpenkov   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
21210ab2aceSGeorge Karpenkov   exit(1);
21310ab2aceSGeorge Karpenkov }
21410ab2aceSGeorge Karpenkov 
SearchRegexCmd(const std::string & Regex)21510ab2aceSGeorge Karpenkov std::string SearchRegexCmd(const std::string &Regex) {
21610ab2aceSGeorge Karpenkov   return "findstr /r \"" + Regex + "\"";
21710ab2aceSGeorge Karpenkov }
21810ab2aceSGeorge Karpenkov 
DiscardOutput(int Fd)219e5b603a4SMarco Vanotti void DiscardOutput(int Fd) {
220e5b603a4SMarco Vanotti   FILE* Temp = fopen("nul", "w");
221e5b603a4SMarco Vanotti   if (!Temp)
222e5b603a4SMarco Vanotti     return;
223e5b603a4SMarco Vanotti   _dup2(_fileno(Temp), Fd);
224e5b603a4SMarco Vanotti   fclose(Temp);
225e5b603a4SMarco Vanotti }
226e5b603a4SMarco Vanotti 
22710ab2aceSGeorge Karpenkov } // namespace fuzzer
22810ab2aceSGeorge Karpenkov 
22910ab2aceSGeorge Karpenkov #endif // LIBFUZZER_WINDOWS
230