1*0b57cec5SDimitry Andric //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric // Misc utils implementation for Windows.
9*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
105ffd83dbSDimitry Andric #include "FuzzerPlatform.h"
11*0b57cec5SDimitry Andric #if LIBFUZZER_WINDOWS
12*0b57cec5SDimitry Andric #include "FuzzerCommand.h"
13*0b57cec5SDimitry Andric #include "FuzzerIO.h"
14*0b57cec5SDimitry Andric #include "FuzzerInternal.h"
15*0b57cec5SDimitry Andric #include <cassert>
16*0b57cec5SDimitry Andric #include <chrono>
17*0b57cec5SDimitry Andric #include <cstring>
18*0b57cec5SDimitry Andric #include <errno.h>
19480093f4SDimitry Andric #include <io.h>
20*0b57cec5SDimitry Andric #include <iomanip>
21*0b57cec5SDimitry Andric #include <signal.h>
22*0b57cec5SDimitry Andric #include <stdio.h>
23*0b57cec5SDimitry Andric #include <sys/types.h>
24*0b57cec5SDimitry Andric #include <windows.h>
25*0b57cec5SDimitry Andric 
26*0b57cec5SDimitry Andric // This must be included after windows.h.
27*0b57cec5SDimitry Andric #include <psapi.h>
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric namespace fuzzer {
30*0b57cec5SDimitry Andric 
31*0b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr;
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
34*0b57cec5SDimitry Andric   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
35*0b57cec5SDimitry Andric     case EXCEPTION_ACCESS_VIOLATION:
36*0b57cec5SDimitry Andric     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
37*0b57cec5SDimitry Andric     case EXCEPTION_STACK_OVERFLOW:
38*0b57cec5SDimitry Andric       if (HandlerOpt->HandleSegv)
39*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
40*0b57cec5SDimitry Andric       break;
41*0b57cec5SDimitry Andric     case EXCEPTION_DATATYPE_MISALIGNMENT:
42*0b57cec5SDimitry Andric     case EXCEPTION_IN_PAGE_ERROR:
43*0b57cec5SDimitry Andric       if (HandlerOpt->HandleBus)
44*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
45*0b57cec5SDimitry Andric       break;
46*0b57cec5SDimitry Andric     case EXCEPTION_ILLEGAL_INSTRUCTION:
47*0b57cec5SDimitry Andric     case EXCEPTION_PRIV_INSTRUCTION:
48*0b57cec5SDimitry Andric       if (HandlerOpt->HandleIll)
49*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
50*0b57cec5SDimitry Andric       break;
51*0b57cec5SDimitry Andric     case EXCEPTION_FLT_DENORMAL_OPERAND:
52*0b57cec5SDimitry Andric     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
53*0b57cec5SDimitry Andric     case EXCEPTION_FLT_INEXACT_RESULT:
54*0b57cec5SDimitry Andric     case EXCEPTION_FLT_INVALID_OPERATION:
55*0b57cec5SDimitry Andric     case EXCEPTION_FLT_OVERFLOW:
56*0b57cec5SDimitry Andric     case EXCEPTION_FLT_STACK_CHECK:
57*0b57cec5SDimitry Andric     case EXCEPTION_FLT_UNDERFLOW:
58*0b57cec5SDimitry Andric     case EXCEPTION_INT_DIVIDE_BY_ZERO:
59*0b57cec5SDimitry Andric     case EXCEPTION_INT_OVERFLOW:
60*0b57cec5SDimitry Andric       if (HandlerOpt->HandleFpe)
61*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
62*0b57cec5SDimitry Andric       break;
63*0b57cec5SDimitry Andric     // TODO: handle (Options.HandleXfsz)
64*0b57cec5SDimitry Andric   }
65*0b57cec5SDimitry Andric   return EXCEPTION_CONTINUE_SEARCH;
66*0b57cec5SDimitry Andric }
67*0b57cec5SDimitry Andric 
68*0b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
69*0b57cec5SDimitry Andric   switch (dwCtrlType) {
70*0b57cec5SDimitry Andric     case CTRL_C_EVENT:
71*0b57cec5SDimitry Andric       if (HandlerOpt->HandleInt)
72*0b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
73*0b57cec5SDimitry Andric       return TRUE;
74*0b57cec5SDimitry Andric     case CTRL_BREAK_EVENT:
75*0b57cec5SDimitry Andric       if (HandlerOpt->HandleTerm)
76*0b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
77*0b57cec5SDimitry Andric       return TRUE;
78*0b57cec5SDimitry Andric   }
79*0b57cec5SDimitry Andric   return FALSE;
80*0b57cec5SDimitry Andric }
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
83*0b57cec5SDimitry Andric   Fuzzer::StaticAlarmCallback();
84*0b57cec5SDimitry Andric }
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric class TimerQ {
87*0b57cec5SDimitry Andric   HANDLE TimerQueue;
88*0b57cec5SDimitry Andric  public:
89*0b57cec5SDimitry Andric   TimerQ() : TimerQueue(NULL) {}
90*0b57cec5SDimitry Andric   ~TimerQ() {
91*0b57cec5SDimitry Andric     if (TimerQueue)
92*0b57cec5SDimitry Andric       DeleteTimerQueueEx(TimerQueue, NULL);
93*0b57cec5SDimitry Andric   }
94*0b57cec5SDimitry Andric   void SetTimer(int Seconds) {
95*0b57cec5SDimitry Andric     if (!TimerQueue) {
96*0b57cec5SDimitry Andric       TimerQueue = CreateTimerQueue();
97*0b57cec5SDimitry Andric       if (!TimerQueue) {
98*0b57cec5SDimitry Andric         Printf("libFuzzer: CreateTimerQueue failed.\n");
99*0b57cec5SDimitry Andric         exit(1);
100*0b57cec5SDimitry Andric       }
101*0b57cec5SDimitry Andric     }
102*0b57cec5SDimitry Andric     HANDLE Timer;
103*0b57cec5SDimitry Andric     if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
104*0b57cec5SDimitry Andric         Seconds*1000, Seconds*1000, 0)) {
105*0b57cec5SDimitry Andric       Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
106*0b57cec5SDimitry Andric       exit(1);
107*0b57cec5SDimitry Andric     }
108*0b57cec5SDimitry Andric   }
109*0b57cec5SDimitry Andric };
110*0b57cec5SDimitry Andric 
111*0b57cec5SDimitry Andric static TimerQ Timer;
112*0b57cec5SDimitry Andric 
113*0b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
114*0b57cec5SDimitry Andric 
115*0b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) {
116*0b57cec5SDimitry Andric   HandlerOpt = &Options;
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric   if (Options.UnitTimeoutSec > 0)
119*0b57cec5SDimitry Andric     Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric   if (Options.HandleInt || Options.HandleTerm)
122*0b57cec5SDimitry Andric     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
123*0b57cec5SDimitry Andric       DWORD LastError = GetLastError();
124*0b57cec5SDimitry Andric       Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
125*0b57cec5SDimitry Andric         LastError);
126*0b57cec5SDimitry Andric       exit(1);
127*0b57cec5SDimitry Andric     }
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric   if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
130*0b57cec5SDimitry Andric       Options.HandleFpe)
131*0b57cec5SDimitry Andric     SetUnhandledExceptionFilter(ExceptionHandler);
132*0b57cec5SDimitry Andric 
133*0b57cec5SDimitry Andric   if (Options.HandleAbrt)
134*0b57cec5SDimitry Andric     if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
135*0b57cec5SDimitry Andric       Printf("libFuzzer: signal failed with %d\n", errno);
136*0b57cec5SDimitry Andric       exit(1);
137*0b57cec5SDimitry Andric     }
138*0b57cec5SDimitry Andric }
139*0b57cec5SDimitry Andric 
140*0b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
141*0b57cec5SDimitry Andric 
142*0b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); }
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric size_t GetPeakRSSMb() {
145*0b57cec5SDimitry Andric   PROCESS_MEMORY_COUNTERS info;
146*0b57cec5SDimitry Andric   if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
147*0b57cec5SDimitry Andric     return 0;
148*0b57cec5SDimitry Andric   return info.PeakWorkingSetSize >> 20;
149*0b57cec5SDimitry Andric }
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) {
152*0b57cec5SDimitry Andric   return _popen(Command, Mode);
153*0b57cec5SDimitry Andric }
154*0b57cec5SDimitry Andric 
1555ffd83dbSDimitry Andric int CloseProcessPipe(FILE *F) {
1565ffd83dbSDimitry Andric   return _pclose(F);
1575ffd83dbSDimitry Andric }
1585ffd83dbSDimitry Andric 
159*0b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) {
160*0b57cec5SDimitry Andric   std::string CmdLine = Cmd.toString();
161*0b57cec5SDimitry Andric   return system(CmdLine.c_str());
162*0b57cec5SDimitry Andric }
163*0b57cec5SDimitry Andric 
1645ffd83dbSDimitry Andric bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
1655ffd83dbSDimitry Andric   FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
1665ffd83dbSDimitry Andric   if (!Pipe)
1675ffd83dbSDimitry Andric     return false;
1685ffd83dbSDimitry Andric 
1695ffd83dbSDimitry Andric   if (CmdOutput) {
1705ffd83dbSDimitry Andric     char TmpBuffer[128];
1715ffd83dbSDimitry Andric     while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
1725ffd83dbSDimitry Andric       CmdOutput->append(TmpBuffer);
1735ffd83dbSDimitry Andric   }
1745ffd83dbSDimitry Andric   return _pclose(Pipe) == 0;
1755ffd83dbSDimitry Andric }
1765ffd83dbSDimitry Andric 
177*0b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
178*0b57cec5SDimitry Andric                          size_t PattLen) {
179*0b57cec5SDimitry Andric   // TODO: make this implementation more efficient.
180*0b57cec5SDimitry Andric   const char *Cdata = (const char *)Data;
181*0b57cec5SDimitry Andric   const char *Cpatt = (const char *)Patt;
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
184*0b57cec5SDimitry Andric     return NULL;
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric   if (PattLen == 1)
187*0b57cec5SDimitry Andric     return memchr(Data, *Cpatt, DataLen);
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric   const char *End = Cdata + DataLen - PattLen + 1;
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric   for (const char *It = Cdata; It < End; ++It)
192*0b57cec5SDimitry Andric     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
193*0b57cec5SDimitry Andric       return It;
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric   return NULL;
196*0b57cec5SDimitry Andric }
197*0b57cec5SDimitry Andric 
198*0b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) {
199*0b57cec5SDimitry Andric   Vector<std::string> command_vector;
200*0b57cec5SDimitry Andric   command_vector.push_back("dumpbin /summary > nul");
201*0b57cec5SDimitry Andric   if (ExecuteCommand(Command(command_vector)) == 0)
202*0b57cec5SDimitry Andric     return "dumpbin /disasm " + FileName;
203*0b57cec5SDimitry Andric   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
204*0b57cec5SDimitry Andric   exit(1);
205*0b57cec5SDimitry Andric }
206*0b57cec5SDimitry Andric 
207*0b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) {
208*0b57cec5SDimitry Andric   return "findstr /r \"" + Regex + "\"";
209*0b57cec5SDimitry Andric }
210*0b57cec5SDimitry Andric 
211480093f4SDimitry Andric void DiscardOutput(int Fd) {
212480093f4SDimitry Andric   FILE* Temp = fopen("nul", "w");
213480093f4SDimitry Andric   if (!Temp)
214480093f4SDimitry Andric     return;
215480093f4SDimitry Andric   _dup2(_fileno(Temp), Fd);
216480093f4SDimitry Andric   fclose(Temp);
217480093f4SDimitry Andric }
218480093f4SDimitry Andric 
219*0b57cec5SDimitry Andric } // namespace fuzzer
220*0b57cec5SDimitry Andric 
221*0b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS
222