13cab2bb3Spatrick //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick // Misc utils implementation for Windows.
93cab2bb3Spatrick //===----------------------------------------------------------------------===//
101f9cb04fSpatrick #include "FuzzerPlatform.h"
113cab2bb3Spatrick #if LIBFUZZER_WINDOWS
123cab2bb3Spatrick #include "FuzzerCommand.h"
133cab2bb3Spatrick #include "FuzzerIO.h"
143cab2bb3Spatrick #include "FuzzerInternal.h"
153cab2bb3Spatrick #include <cassert>
163cab2bb3Spatrick #include <chrono>
173cab2bb3Spatrick #include <cstring>
183cab2bb3Spatrick #include <errno.h>
193cab2bb3Spatrick #include <io.h>
203cab2bb3Spatrick #include <iomanip>
213cab2bb3Spatrick #include <signal.h>
223cab2bb3Spatrick #include <stdio.h>
233cab2bb3Spatrick #include <sys/types.h>
243cab2bb3Spatrick #include <windows.h>
253cab2bb3Spatrick
263cab2bb3Spatrick // This must be included after windows.h.
273cab2bb3Spatrick #include <psapi.h>
283cab2bb3Spatrick
293cab2bb3Spatrick namespace fuzzer {
303cab2bb3Spatrick
313cab2bb3Spatrick static const FuzzingOptions* HandlerOpt = nullptr;
323cab2bb3Spatrick
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)333cab2bb3Spatrick static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
343cab2bb3Spatrick switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
353cab2bb3Spatrick case EXCEPTION_ACCESS_VIOLATION:
363cab2bb3Spatrick case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
373cab2bb3Spatrick case EXCEPTION_STACK_OVERFLOW:
383cab2bb3Spatrick if (HandlerOpt->HandleSegv)
393cab2bb3Spatrick Fuzzer::StaticCrashSignalCallback();
403cab2bb3Spatrick break;
413cab2bb3Spatrick case EXCEPTION_DATATYPE_MISALIGNMENT:
423cab2bb3Spatrick case EXCEPTION_IN_PAGE_ERROR:
433cab2bb3Spatrick if (HandlerOpt->HandleBus)
443cab2bb3Spatrick Fuzzer::StaticCrashSignalCallback();
453cab2bb3Spatrick break;
463cab2bb3Spatrick case EXCEPTION_ILLEGAL_INSTRUCTION:
473cab2bb3Spatrick case EXCEPTION_PRIV_INSTRUCTION:
483cab2bb3Spatrick if (HandlerOpt->HandleIll)
493cab2bb3Spatrick Fuzzer::StaticCrashSignalCallback();
503cab2bb3Spatrick break;
513cab2bb3Spatrick case EXCEPTION_FLT_DENORMAL_OPERAND:
523cab2bb3Spatrick case EXCEPTION_FLT_DIVIDE_BY_ZERO:
533cab2bb3Spatrick case EXCEPTION_FLT_INEXACT_RESULT:
543cab2bb3Spatrick case EXCEPTION_FLT_INVALID_OPERATION:
553cab2bb3Spatrick case EXCEPTION_FLT_OVERFLOW:
563cab2bb3Spatrick case EXCEPTION_FLT_STACK_CHECK:
573cab2bb3Spatrick case EXCEPTION_FLT_UNDERFLOW:
583cab2bb3Spatrick case EXCEPTION_INT_DIVIDE_BY_ZERO:
593cab2bb3Spatrick case EXCEPTION_INT_OVERFLOW:
603cab2bb3Spatrick if (HandlerOpt->HandleFpe)
613cab2bb3Spatrick Fuzzer::StaticCrashSignalCallback();
623cab2bb3Spatrick break;
63d89ec533Spatrick // This is an undocumented exception code corresponding to a Visual C++
64d89ec533Spatrick // Exception.
65d89ec533Spatrick //
66d89ec533Spatrick // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
67d89ec533Spatrick case 0xE06D7363:
68d89ec533Spatrick if (HandlerOpt->HandleWinExcept)
69d89ec533Spatrick Fuzzer::StaticCrashSignalCallback();
70d89ec533Spatrick break;
71d89ec533Spatrick // TODO: Handle (Options.HandleXfsz)
723cab2bb3Spatrick }
733cab2bb3Spatrick return EXCEPTION_CONTINUE_SEARCH;
743cab2bb3Spatrick }
753cab2bb3Spatrick
CtrlHandler(DWORD dwCtrlType)763cab2bb3Spatrick BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
773cab2bb3Spatrick switch (dwCtrlType) {
783cab2bb3Spatrick case CTRL_C_EVENT:
793cab2bb3Spatrick if (HandlerOpt->HandleInt)
803cab2bb3Spatrick Fuzzer::StaticInterruptCallback();
813cab2bb3Spatrick return TRUE;
823cab2bb3Spatrick case CTRL_BREAK_EVENT:
833cab2bb3Spatrick if (HandlerOpt->HandleTerm)
843cab2bb3Spatrick Fuzzer::StaticInterruptCallback();
853cab2bb3Spatrick return TRUE;
863cab2bb3Spatrick }
873cab2bb3Spatrick return FALSE;
883cab2bb3Spatrick }
893cab2bb3Spatrick
AlarmHandler(PVOID,BOOLEAN)903cab2bb3Spatrick void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
913cab2bb3Spatrick Fuzzer::StaticAlarmCallback();
923cab2bb3Spatrick }
933cab2bb3Spatrick
943cab2bb3Spatrick class TimerQ {
953cab2bb3Spatrick HANDLE TimerQueue;
963cab2bb3Spatrick public:
TimerQ()973cab2bb3Spatrick TimerQ() : TimerQueue(NULL) {}
~TimerQ()983cab2bb3Spatrick ~TimerQ() {
993cab2bb3Spatrick if (TimerQueue)
1003cab2bb3Spatrick DeleteTimerQueueEx(TimerQueue, NULL);
1013cab2bb3Spatrick }
SetTimer(int Seconds)1023cab2bb3Spatrick void SetTimer(int Seconds) {
1033cab2bb3Spatrick if (!TimerQueue) {
1043cab2bb3Spatrick TimerQueue = CreateTimerQueue();
1053cab2bb3Spatrick if (!TimerQueue) {
1063cab2bb3Spatrick Printf("libFuzzer: CreateTimerQueue failed.\n");
1073cab2bb3Spatrick exit(1);
1083cab2bb3Spatrick }
1093cab2bb3Spatrick }
1103cab2bb3Spatrick HANDLE Timer;
1113cab2bb3Spatrick if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
1123cab2bb3Spatrick Seconds*1000, Seconds*1000, 0)) {
1133cab2bb3Spatrick Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
1143cab2bb3Spatrick exit(1);
1153cab2bb3Spatrick }
1163cab2bb3Spatrick }
1173cab2bb3Spatrick };
1183cab2bb3Spatrick
1193cab2bb3Spatrick static TimerQ Timer;
1203cab2bb3Spatrick
CrashHandler(int)1213cab2bb3Spatrick static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
1223cab2bb3Spatrick
SetSignalHandler(const FuzzingOptions & Options)1233cab2bb3Spatrick void SetSignalHandler(const FuzzingOptions& Options) {
1243cab2bb3Spatrick HandlerOpt = &Options;
1253cab2bb3Spatrick
126d89ec533Spatrick if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
1273cab2bb3Spatrick Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
1283cab2bb3Spatrick
1293cab2bb3Spatrick if (Options.HandleInt || Options.HandleTerm)
1303cab2bb3Spatrick if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
1313cab2bb3Spatrick DWORD LastError = GetLastError();
1323cab2bb3Spatrick Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
1333cab2bb3Spatrick LastError);
1343cab2bb3Spatrick exit(1);
1353cab2bb3Spatrick }
1363cab2bb3Spatrick
1373cab2bb3Spatrick if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
138d89ec533Spatrick Options.HandleFpe || Options.HandleWinExcept)
1393cab2bb3Spatrick SetUnhandledExceptionFilter(ExceptionHandler);
1403cab2bb3Spatrick
1413cab2bb3Spatrick if (Options.HandleAbrt)
1423cab2bb3Spatrick if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
1433cab2bb3Spatrick Printf("libFuzzer: signal failed with %d\n", errno);
1443cab2bb3Spatrick exit(1);
1453cab2bb3Spatrick }
1463cab2bb3Spatrick }
1473cab2bb3Spatrick
SleepSeconds(int Seconds)1483cab2bb3Spatrick void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
1493cab2bb3Spatrick
GetPid()1503cab2bb3Spatrick unsigned long GetPid() { return GetCurrentProcessId(); }
1513cab2bb3Spatrick
GetPeakRSSMb()1523cab2bb3Spatrick size_t GetPeakRSSMb() {
1533cab2bb3Spatrick PROCESS_MEMORY_COUNTERS info;
1543cab2bb3Spatrick if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
1553cab2bb3Spatrick return 0;
1563cab2bb3Spatrick return info.PeakWorkingSetSize >> 20;
1573cab2bb3Spatrick }
1583cab2bb3Spatrick
OpenProcessPipe(const char * Command,const char * Mode)1593cab2bb3Spatrick FILE *OpenProcessPipe(const char *Command, const char *Mode) {
1603cab2bb3Spatrick return _popen(Command, Mode);
1613cab2bb3Spatrick }
1623cab2bb3Spatrick
CloseProcessPipe(FILE * F)1631f9cb04fSpatrick int CloseProcessPipe(FILE *F) {
1641f9cb04fSpatrick return _pclose(F);
1651f9cb04fSpatrick }
1661f9cb04fSpatrick
ExecuteCommand(const Command & Cmd)1673cab2bb3Spatrick int ExecuteCommand(const Command &Cmd) {
1683cab2bb3Spatrick std::string CmdLine = Cmd.toString();
1693cab2bb3Spatrick return system(CmdLine.c_str());
1703cab2bb3Spatrick }
1713cab2bb3Spatrick
ExecuteCommand(const Command & Cmd,std::string * CmdOutput)1721f9cb04fSpatrick bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
1731f9cb04fSpatrick FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
1741f9cb04fSpatrick if (!Pipe)
1751f9cb04fSpatrick return false;
1761f9cb04fSpatrick
1771f9cb04fSpatrick if (CmdOutput) {
1781f9cb04fSpatrick char TmpBuffer[128];
1791f9cb04fSpatrick while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
1801f9cb04fSpatrick CmdOutput->append(TmpBuffer);
1811f9cb04fSpatrick }
1821f9cb04fSpatrick return _pclose(Pipe) == 0;
1831f9cb04fSpatrick }
1841f9cb04fSpatrick
SearchMemory(const void * Data,size_t DataLen,const void * Patt,size_t PattLen)1853cab2bb3Spatrick const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
1863cab2bb3Spatrick size_t PattLen) {
1873cab2bb3Spatrick // TODO: make this implementation more efficient.
1883cab2bb3Spatrick const char *Cdata = (const char *)Data;
1893cab2bb3Spatrick const char *Cpatt = (const char *)Patt;
1903cab2bb3Spatrick
1913cab2bb3Spatrick if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
1923cab2bb3Spatrick return NULL;
1933cab2bb3Spatrick
1943cab2bb3Spatrick if (PattLen == 1)
1953cab2bb3Spatrick return memchr(Data, *Cpatt, DataLen);
1963cab2bb3Spatrick
1973cab2bb3Spatrick const char *End = Cdata + DataLen - PattLen + 1;
1983cab2bb3Spatrick
1993cab2bb3Spatrick for (const char *It = Cdata; It < End; ++It)
2003cab2bb3Spatrick if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
2013cab2bb3Spatrick return It;
2023cab2bb3Spatrick
2033cab2bb3Spatrick return NULL;
2043cab2bb3Spatrick }
2053cab2bb3Spatrick
DisassembleCmd(const std::string & FileName)2063cab2bb3Spatrick std::string DisassembleCmd(const std::string &FileName) {
207*810390e3Srobert std::vector<std::string> command_vector;
2083cab2bb3Spatrick command_vector.push_back("dumpbin /summary > nul");
2093cab2bb3Spatrick if (ExecuteCommand(Command(command_vector)) == 0)
2103cab2bb3Spatrick return "dumpbin /disasm " + FileName;
2113cab2bb3Spatrick Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
2123cab2bb3Spatrick exit(1);
2133cab2bb3Spatrick }
2143cab2bb3Spatrick
SearchRegexCmd(const std::string & Regex)2153cab2bb3Spatrick std::string SearchRegexCmd(const std::string &Regex) {
2163cab2bb3Spatrick return "findstr /r \"" + Regex + "\"";
2173cab2bb3Spatrick }
2183cab2bb3Spatrick
DiscardOutput(int Fd)2193cab2bb3Spatrick void DiscardOutput(int Fd) {
2203cab2bb3Spatrick FILE* Temp = fopen("nul", "w");
2213cab2bb3Spatrick if (!Temp)
2223cab2bb3Spatrick return;
2233cab2bb3Spatrick _dup2(_fileno(Temp), Fd);
2243cab2bb3Spatrick fclose(Temp);
2253cab2bb3Spatrick }
2263cab2bb3Spatrick
2273cab2bb3Spatrick } // namespace fuzzer
2283cab2bb3Spatrick
2293cab2bb3Spatrick #endif // LIBFUZZER_WINDOWS
230