xref: /freebsd/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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 //===----------------------------------------------------------------------===//
10*0b57cec5SDimitry Andric #include "FuzzerDefs.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>
19*0b57cec5SDimitry Andric #include <iomanip>
20*0b57cec5SDimitry Andric #include <signal.h>
21*0b57cec5SDimitry Andric #include <stdio.h>
22*0b57cec5SDimitry Andric #include <sys/types.h>
23*0b57cec5SDimitry Andric #include <windows.h>
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric // This must be included after windows.h.
26*0b57cec5SDimitry Andric #include <psapi.h>
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric namespace fuzzer {
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr;
31*0b57cec5SDimitry Andric 
32*0b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
33*0b57cec5SDimitry Andric   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
34*0b57cec5SDimitry Andric     case EXCEPTION_ACCESS_VIOLATION:
35*0b57cec5SDimitry Andric     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
36*0b57cec5SDimitry Andric     case EXCEPTION_STACK_OVERFLOW:
37*0b57cec5SDimitry Andric       if (HandlerOpt->HandleSegv)
38*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
39*0b57cec5SDimitry Andric       break;
40*0b57cec5SDimitry Andric     case EXCEPTION_DATATYPE_MISALIGNMENT:
41*0b57cec5SDimitry Andric     case EXCEPTION_IN_PAGE_ERROR:
42*0b57cec5SDimitry Andric       if (HandlerOpt->HandleBus)
43*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
44*0b57cec5SDimitry Andric       break;
45*0b57cec5SDimitry Andric     case EXCEPTION_ILLEGAL_INSTRUCTION:
46*0b57cec5SDimitry Andric     case EXCEPTION_PRIV_INSTRUCTION:
47*0b57cec5SDimitry Andric       if (HandlerOpt->HandleIll)
48*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
49*0b57cec5SDimitry Andric       break;
50*0b57cec5SDimitry Andric     case EXCEPTION_FLT_DENORMAL_OPERAND:
51*0b57cec5SDimitry Andric     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
52*0b57cec5SDimitry Andric     case EXCEPTION_FLT_INEXACT_RESULT:
53*0b57cec5SDimitry Andric     case EXCEPTION_FLT_INVALID_OPERATION:
54*0b57cec5SDimitry Andric     case EXCEPTION_FLT_OVERFLOW:
55*0b57cec5SDimitry Andric     case EXCEPTION_FLT_STACK_CHECK:
56*0b57cec5SDimitry Andric     case EXCEPTION_FLT_UNDERFLOW:
57*0b57cec5SDimitry Andric     case EXCEPTION_INT_DIVIDE_BY_ZERO:
58*0b57cec5SDimitry Andric     case EXCEPTION_INT_OVERFLOW:
59*0b57cec5SDimitry Andric       if (HandlerOpt->HandleFpe)
60*0b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
61*0b57cec5SDimitry Andric       break;
62*0b57cec5SDimitry Andric     // TODO: handle (Options.HandleXfsz)
63*0b57cec5SDimitry Andric   }
64*0b57cec5SDimitry Andric   return EXCEPTION_CONTINUE_SEARCH;
65*0b57cec5SDimitry Andric }
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
68*0b57cec5SDimitry Andric   switch (dwCtrlType) {
69*0b57cec5SDimitry Andric     case CTRL_C_EVENT:
70*0b57cec5SDimitry Andric       if (HandlerOpt->HandleInt)
71*0b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
72*0b57cec5SDimitry Andric       return TRUE;
73*0b57cec5SDimitry Andric     case CTRL_BREAK_EVENT:
74*0b57cec5SDimitry Andric       if (HandlerOpt->HandleTerm)
75*0b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
76*0b57cec5SDimitry Andric       return TRUE;
77*0b57cec5SDimitry Andric   }
78*0b57cec5SDimitry Andric   return FALSE;
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
82*0b57cec5SDimitry Andric   Fuzzer::StaticAlarmCallback();
83*0b57cec5SDimitry Andric }
84*0b57cec5SDimitry Andric 
85*0b57cec5SDimitry Andric class TimerQ {
86*0b57cec5SDimitry Andric   HANDLE TimerQueue;
87*0b57cec5SDimitry Andric  public:
88*0b57cec5SDimitry Andric   TimerQ() : TimerQueue(NULL) {}
89*0b57cec5SDimitry Andric   ~TimerQ() {
90*0b57cec5SDimitry Andric     if (TimerQueue)
91*0b57cec5SDimitry Andric       DeleteTimerQueueEx(TimerQueue, NULL);
92*0b57cec5SDimitry Andric   }
93*0b57cec5SDimitry Andric   void SetTimer(int Seconds) {
94*0b57cec5SDimitry Andric     if (!TimerQueue) {
95*0b57cec5SDimitry Andric       TimerQueue = CreateTimerQueue();
96*0b57cec5SDimitry Andric       if (!TimerQueue) {
97*0b57cec5SDimitry Andric         Printf("libFuzzer: CreateTimerQueue failed.\n");
98*0b57cec5SDimitry Andric         exit(1);
99*0b57cec5SDimitry Andric       }
100*0b57cec5SDimitry Andric     }
101*0b57cec5SDimitry Andric     HANDLE Timer;
102*0b57cec5SDimitry Andric     if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
103*0b57cec5SDimitry Andric         Seconds*1000, Seconds*1000, 0)) {
104*0b57cec5SDimitry Andric       Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
105*0b57cec5SDimitry Andric       exit(1);
106*0b57cec5SDimitry Andric     }
107*0b57cec5SDimitry Andric   }
108*0b57cec5SDimitry Andric };
109*0b57cec5SDimitry Andric 
110*0b57cec5SDimitry Andric static TimerQ Timer;
111*0b57cec5SDimitry Andric 
112*0b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
115*0b57cec5SDimitry Andric   return false;  // UNIMPLEMENTED
116*0b57cec5SDimitry Andric }
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) {
119*0b57cec5SDimitry Andric   HandlerOpt = &Options;
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric   if (Options.UnitTimeoutSec > 0)
122*0b57cec5SDimitry Andric     Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
123*0b57cec5SDimitry Andric 
124*0b57cec5SDimitry Andric   if (Options.HandleInt || Options.HandleTerm)
125*0b57cec5SDimitry Andric     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
126*0b57cec5SDimitry Andric       DWORD LastError = GetLastError();
127*0b57cec5SDimitry Andric       Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
128*0b57cec5SDimitry Andric         LastError);
129*0b57cec5SDimitry Andric       exit(1);
130*0b57cec5SDimitry Andric     }
131*0b57cec5SDimitry Andric 
132*0b57cec5SDimitry Andric   if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
133*0b57cec5SDimitry Andric       Options.HandleFpe)
134*0b57cec5SDimitry Andric     SetUnhandledExceptionFilter(ExceptionHandler);
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric   if (Options.HandleAbrt)
137*0b57cec5SDimitry Andric     if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
138*0b57cec5SDimitry Andric       Printf("libFuzzer: signal failed with %d\n", errno);
139*0b57cec5SDimitry Andric       exit(1);
140*0b57cec5SDimitry Andric     }
141*0b57cec5SDimitry Andric }
142*0b57cec5SDimitry Andric 
143*0b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); }
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric size_t GetPeakRSSMb() {
148*0b57cec5SDimitry Andric   PROCESS_MEMORY_COUNTERS info;
149*0b57cec5SDimitry Andric   if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
150*0b57cec5SDimitry Andric     return 0;
151*0b57cec5SDimitry Andric   return info.PeakWorkingSetSize >> 20;
152*0b57cec5SDimitry Andric }
153*0b57cec5SDimitry Andric 
154*0b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) {
155*0b57cec5SDimitry Andric   return _popen(Command, Mode);
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) {
159*0b57cec5SDimitry Andric   std::string CmdLine = Cmd.toString();
160*0b57cec5SDimitry Andric   return system(CmdLine.c_str());
161*0b57cec5SDimitry Andric }
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
164*0b57cec5SDimitry Andric                          size_t PattLen) {
165*0b57cec5SDimitry Andric   // TODO: make this implementation more efficient.
166*0b57cec5SDimitry Andric   const char *Cdata = (const char *)Data;
167*0b57cec5SDimitry Andric   const char *Cpatt = (const char *)Patt;
168*0b57cec5SDimitry Andric 
169*0b57cec5SDimitry Andric   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
170*0b57cec5SDimitry Andric     return NULL;
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric   if (PattLen == 1)
173*0b57cec5SDimitry Andric     return memchr(Data, *Cpatt, DataLen);
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric   const char *End = Cdata + DataLen - PattLen + 1;
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric   for (const char *It = Cdata; It < End; ++It)
178*0b57cec5SDimitry Andric     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
179*0b57cec5SDimitry Andric       return It;
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric   return NULL;
182*0b57cec5SDimitry Andric }
183*0b57cec5SDimitry Andric 
184*0b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) {
185*0b57cec5SDimitry Andric   Vector<std::string> command_vector;
186*0b57cec5SDimitry Andric   command_vector.push_back("dumpbin /summary > nul");
187*0b57cec5SDimitry Andric   if (ExecuteCommand(Command(command_vector)) == 0)
188*0b57cec5SDimitry Andric     return "dumpbin /disasm " + FileName;
189*0b57cec5SDimitry Andric   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
190*0b57cec5SDimitry Andric   exit(1);
191*0b57cec5SDimitry Andric }
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) {
194*0b57cec5SDimitry Andric   return "findstr /r \"" + Regex + "\"";
195*0b57cec5SDimitry Andric }
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric } // namespace fuzzer
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS
200