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 "FuzzerIO.h"
14#include "FuzzerInternal.h"
15#include <cassert>
16#include <chrono>
17#include <cstring>
18#include <errno.h>
19#include <iomanip>
20#include <signal.h>
21#include <sstream>
22#include <stdio.h>
23#include <sys/types.h>
24#include <windows.h>
25#include <Psapi.h>
26
27namespace fuzzer {
28
29static const FuzzingOptions* HandlerOpt = nullptr;
30
31LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
32  switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
33    case EXCEPTION_ACCESS_VIOLATION:
34    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
35    case EXCEPTION_STACK_OVERFLOW:
36      if (HandlerOpt->HandleSegv)
37        Fuzzer::StaticCrashSignalCallback();
38      break;
39    case EXCEPTION_DATATYPE_MISALIGNMENT:
40    case EXCEPTION_IN_PAGE_ERROR:
41      if (HandlerOpt->HandleBus)
42        Fuzzer::StaticCrashSignalCallback();
43      break;
44    case EXCEPTION_ILLEGAL_INSTRUCTION:
45    case EXCEPTION_PRIV_INSTRUCTION:
46      if (HandlerOpt->HandleIll)
47        Fuzzer::StaticCrashSignalCallback();
48      break;
49    case EXCEPTION_FLT_DENORMAL_OPERAND:
50    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
51    case EXCEPTION_FLT_INEXACT_RESULT:
52    case EXCEPTION_FLT_INVALID_OPERATION:
53    case EXCEPTION_FLT_OVERFLOW:
54    case EXCEPTION_FLT_STACK_CHECK:
55    case EXCEPTION_FLT_UNDERFLOW:
56    case EXCEPTION_INT_DIVIDE_BY_ZERO:
57    case EXCEPTION_INT_OVERFLOW:
58      if (HandlerOpt->HandleFpe)
59        Fuzzer::StaticCrashSignalCallback();
60      break;
61  }
62  return EXCEPTION_CONTINUE_SEARCH;
63}
64
65BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
66  switch (dwCtrlType) {
67    case CTRL_C_EVENT:
68      if (HandlerOpt->HandleInt)
69        Fuzzer::StaticInterruptCallback();
70      return TRUE;
71    case CTRL_BREAK_EVENT:
72      if (HandlerOpt->HandleTerm)
73        Fuzzer::StaticInterruptCallback();
74      return TRUE;
75  }
76  return FALSE;
77}
78
79void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
80  Fuzzer::StaticAlarmCallback();
81}
82
83class TimerQ {
84  HANDLE TimerQueue;
85 public:
86  TimerQ() : TimerQueue(NULL) {};
87  ~TimerQ() {
88    if (TimerQueue)
89      DeleteTimerQueueEx(TimerQueue, NULL);
90  };
91  void SetTimer(int Seconds) {
92    if (!TimerQueue) {
93      TimerQueue = CreateTimerQueue();
94      if (!TimerQueue) {
95        Printf("libFuzzer: CreateTimerQueue failed.\n");
96        exit(1);
97      }
98    }
99    HANDLE Timer;
100    if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
101        Seconds*1000, Seconds*1000, 0)) {
102      Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
103      exit(1);
104    }
105  };
106};
107
108static TimerQ Timer;
109
110static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
111
112void SetSignalHandler(const FuzzingOptions& Options) {
113  HandlerOpt = &Options;
114
115  if (Options.UnitTimeoutSec > 0)
116    Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
117
118  if (Options.HandleInt || Options.HandleTerm)
119    if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
120      DWORD LastError = GetLastError();
121      Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
122        LastError);
123      exit(1);
124    }
125
126  if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
127      Options.HandleFpe)
128    if (!AddVectoredExceptionHandler(1, ExceptionHandler)) {
129      Printf("libFuzzer: AddVectoredExceptionHandler failed.\n");
130      exit(1);
131    }
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 std::string &Command) {
156  return system(Command.c_str());
157}
158
159const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
160                         size_t PattLen) {
161  // TODO: make this implementation more efficient.
162  const char *Cdata = (const char *)Data;
163  const char *Cpatt = (const char *)Patt;
164
165  if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
166    return NULL;
167
168  if (PattLen == 1)
169    return memchr(Data, *Cpatt, DataLen);
170
171  const char *End = Cdata + DataLen - PattLen + 1;
172
173  for (const char *It = Cdata; It < End; ++It)
174    if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
175      return It;
176
177  return NULL;
178}
179
180} // namespace fuzzer
181
182#endif // LIBFUZZER_WINDOWS
183