1 //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // Misc utils implementation for Windows.
9 //===----------------------------------------------------------------------===//
10 #include "FuzzerPlatform.h"
12 #include "FuzzerCommand.h"
14 #include "FuzzerInternal.h"
23 #include <sys/types.h>
26 // This must be included after windows.h.
31 static const FuzzingOptions* HandlerOpt = nullptr;
33 static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
34 switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
35 case EXCEPTION_ACCESS_VIOLATION:
36 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
37 case EXCEPTION_STACK_OVERFLOW:
38 if (HandlerOpt->HandleSegv)
39 Fuzzer::StaticCrashSignalCallback();
41 case EXCEPTION_DATATYPE_MISALIGNMENT:
42 case EXCEPTION_IN_PAGE_ERROR:
43 if (HandlerOpt->HandleBus)
44 Fuzzer::StaticCrashSignalCallback();
46 case EXCEPTION_ILLEGAL_INSTRUCTION:
47 case EXCEPTION_PRIV_INSTRUCTION:
48 if (HandlerOpt->HandleIll)
49 Fuzzer::StaticCrashSignalCallback();
51 case EXCEPTION_FLT_DENORMAL_OPERAND:
52 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
53 case EXCEPTION_FLT_INEXACT_RESULT:
54 case EXCEPTION_FLT_INVALID_OPERATION:
55 case EXCEPTION_FLT_OVERFLOW:
56 case EXCEPTION_FLT_STACK_CHECK:
57 case EXCEPTION_FLT_UNDERFLOW:
58 case EXCEPTION_INT_DIVIDE_BY_ZERO:
59 case EXCEPTION_INT_OVERFLOW:
60 if (HandlerOpt->HandleFpe)
61 Fuzzer::StaticCrashSignalCallback();
63 // This is an undocumented exception code corresponding to a Visual C++
66 // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
68 if (HandlerOpt->HandleWinExcept)
69 Fuzzer::StaticCrashSignalCallback();
71 // TODO: Handle (Options.HandleXfsz)
73 return EXCEPTION_CONTINUE_SEARCH;
76 BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
79 if (HandlerOpt->HandleInt)
80 Fuzzer::StaticInterruptCallback();
82 case CTRL_BREAK_EVENT:
83 if (HandlerOpt->HandleTerm)
84 Fuzzer::StaticInterruptCallback();
90 void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
91 Fuzzer::StaticAlarmCallback();
97 TimerQ() : TimerQueue(NULL) {}
100 DeleteTimerQueueEx(TimerQueue, NULL);
102 void SetTimer(int Seconds) {
104 TimerQueue = CreateTimerQueue();
106 Printf("libFuzzer: CreateTimerQueue failed.\n");
111 if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
112 Seconds*1000, Seconds*1000, 0)) {
113 Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
121 static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
123 void SetSignalHandler(const FuzzingOptions& Options) {
124 HandlerOpt = &Options;
126 if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
127 Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
129 if (Options.HandleInt || Options.HandleTerm)
130 if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
131 DWORD LastError = GetLastError();
132 Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
137 if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
138 Options.HandleFpe || Options.HandleWinExcept)
139 SetUnhandledExceptionFilter(ExceptionHandler);
141 if (Options.HandleAbrt)
142 if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
143 Printf("libFuzzer: signal failed with %d\n", errno);
148 void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
150 unsigned long GetPid() { return GetCurrentProcessId(); }
152 size_t GetPeakRSSMb() {
153 PROCESS_MEMORY_COUNTERS info;
154 if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
156 return info.PeakWorkingSetSize >> 20;
159 FILE *OpenProcessPipe(const char *Command, const char *Mode) {
160 return _popen(Command, Mode);
163 int CloseProcessPipe(FILE *F) {
167 int ExecuteCommand(const Command &Cmd) {
168 std::string CmdLine = Cmd.toString();
169 return system(CmdLine.c_str());
172 bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
173 FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
179 while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
180 CmdOutput->append(TmpBuffer);
182 return _pclose(Pipe) == 0;
185 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
187 // TODO: make this implementation more efficient.
188 const char *Cdata = (const char *)Data;
189 const char *Cpatt = (const char *)Patt;
191 if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
195 return memchr(Data, *Cpatt, DataLen);
197 const char *End = Cdata + DataLen - PattLen + 1;
199 for (const char *It = Cdata; It < End; ++It)
200 if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
206 std::string DisassembleCmd(const std::string &FileName) {
207 Vector<std::string> command_vector;
208 command_vector.push_back("dumpbin /summary > nul");
209 if (ExecuteCommand(Command(command_vector)) == 0)
210 return "dumpbin /disasm " + FileName;
211 Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
215 std::string SearchRegexCmd(const std::string &Regex) {
216 return "findstr /r \"" + Regex + "\"";
219 void DiscardOutput(int Fd) {
220 FILE* Temp = fopen("nul", "w");
223 _dup2(_fileno(Temp), Fd);
227 } // namespace fuzzer
229 #endif // LIBFUZZER_WINDOWS