1//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// Misc utils implementation for Windows.
10//===----------------------------------------------------------------------===//
11#include "FuzzerDefs.h"
12#if LIBFUZZER_WINDOWS
13#include "FuzzerCommand.h"
14#include "FuzzerIO.h"
15#include "FuzzerInternal.h"
16#include <cassert>
17#include <chrono>
18#include <cstring>
19#include <errno.h>
20#include <iomanip>
21#include <signal.h>
22#include <stdio.h>
23#include <sys/types.h>
24#include <windows.h>
25
26// This must be included after windows.h.
27#include <psapi.h>
28
29namespace fuzzer {
30
31static const FuzzingOptions* HandlerOpt = nullptr;
32
33static 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();
40      break;
41    case EXCEPTION_DATATYPE_MISALIGNMENT:
42    case EXCEPTION_IN_PAGE_ERROR:
43      if (HandlerOpt->HandleBus)
44        Fuzzer::StaticCrashSignalCallback();
45      break;
46    case EXCEPTION_ILLEGAL_INSTRUCTION:
47    case EXCEPTION_PRIV_INSTRUCTION:
48      if (HandlerOpt->HandleIll)
49        Fuzzer::StaticCrashSignalCallback();
50      break;
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();
62      break;
63    // TODO: handle (Options.HandleXfsz)
64  }
65  return EXCEPTION_CONTINUE_SEARCH;
66}
67
68BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
69  switch (dwCtrlType) {
70    case CTRL_C_EVENT:
71      if (HandlerOpt->HandleInt)
72        Fuzzer::StaticInterruptCallback();
73      return TRUE;
74    case CTRL_BREAK_EVENT:
75      if (HandlerOpt->HandleTerm)
76        Fuzzer::StaticInterruptCallback();
77      return TRUE;
78  }
79  return FALSE;
80}
81
82void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
83  Fuzzer::StaticAlarmCallback();
84}
85
86class TimerQ {
87  HANDLE TimerQueue;
88 public:
89  TimerQ() : TimerQueue(NULL) {};
90  ~TimerQ() {
91    if (TimerQueue)
92      DeleteTimerQueueEx(TimerQueue, NULL);
93  };
94  void SetTimer(int Seconds) {
95    if (!TimerQueue) {
96      TimerQueue = CreateTimerQueue();
97      if (!TimerQueue) {
98        Printf("libFuzzer: CreateTimerQueue failed.\n");
99        exit(1);
100      }
101    }
102    HANDLE Timer;
103    if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
104        Seconds*1000, Seconds*1000, 0)) {
105      Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
106      exit(1);
107    }
108  };
109};
110
111static TimerQ Timer;
112
113static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
114
115void SetSignalHandler(const FuzzingOptions& Options) {
116  HandlerOpt = &Options;
117
118  if (Options.UnitTimeoutSec > 0)
119    Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
120
121  if (Options.HandleInt || Options.HandleTerm)
122    if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
123      DWORD LastError = GetLastError();
124      Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
125        LastError);
126      exit(1);
127    }
128
129  if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
130      Options.HandleFpe)
131    SetUnhandledExceptionFilter(ExceptionHandler);
132
133  if (Options.HandleAbrt)
134    if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
135      Printf("libFuzzer: signal failed with %d\n", errno);
136      exit(1);
137    }
138}
139
140void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
141
142unsigned long GetPid() { return GetCurrentProcessId(); }
143
144size_t GetPeakRSSMb() {
145  PROCESS_MEMORY_COUNTERS info;
146  if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
147    return 0;
148  return info.PeakWorkingSetSize >> 20;
149}
150
151FILE *OpenProcessPipe(const char *Command, const char *Mode) {
152  return _popen(Command, Mode);
153}
154
155int ExecuteCommand(const Command &Cmd) {
156  std::string CmdLine = Cmd.toString();
157  return system(CmdLine.c_str());
158}
159
160const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
161                         size_t PattLen) {
162  // TODO: make this implementation more efficient.
163  const char *Cdata = (const char *)Data;
164  const char *Cpatt = (const char *)Patt;
165
166  if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
167    return NULL;
168
169  if (PattLen == 1)
170    return memchr(Data, *Cpatt, DataLen);
171
172  const char *End = Cdata + DataLen - PattLen + 1;
173
174  for (const char *It = Cdata; It < End; ++It)
175    if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
176      return It;
177
178  return NULL;
179}
180
181std::string DisassembleCmd(const std::string &FileName) {
182  Vector<std::string> command_vector;
183  command_vector.push_back("dumpbin /summary > nul");
184  if (ExecuteCommand(Command(command_vector)) == 0)
185    return "dumpbin /disasm " + FileName;
186  Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
187  exit(1);
188}
189
190std::string SearchRegexCmd(const std::string &Regex) {
191  return "findstr /r \"" + Regex + "\"";
192}
193
194} // namespace fuzzer
195
196#endif // LIBFUZZER_WINDOWS
197