xref: /freebsd/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
10b57cec5SDimitry Andric //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // Misc utils implementation for Windows.
90b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10*5ffd83dbSDimitry Andric #include "FuzzerPlatform.h"
110b57cec5SDimitry Andric #if LIBFUZZER_WINDOWS
120b57cec5SDimitry Andric #include "FuzzerCommand.h"
130b57cec5SDimitry Andric #include "FuzzerIO.h"
140b57cec5SDimitry Andric #include "FuzzerInternal.h"
150b57cec5SDimitry Andric #include <cassert>
160b57cec5SDimitry Andric #include <chrono>
170b57cec5SDimitry Andric #include <cstring>
180b57cec5SDimitry Andric #include <errno.h>
19480093f4SDimitry Andric #include <io.h>
200b57cec5SDimitry Andric #include <iomanip>
210b57cec5SDimitry Andric #include <signal.h>
220b57cec5SDimitry Andric #include <stdio.h>
230b57cec5SDimitry Andric #include <sys/types.h>
240b57cec5SDimitry Andric #include <windows.h>
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric // This must be included after windows.h.
270b57cec5SDimitry Andric #include <psapi.h>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace fuzzer {
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
340b57cec5SDimitry Andric   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
350b57cec5SDimitry Andric     case EXCEPTION_ACCESS_VIOLATION:
360b57cec5SDimitry Andric     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
370b57cec5SDimitry Andric     case EXCEPTION_STACK_OVERFLOW:
380b57cec5SDimitry Andric       if (HandlerOpt->HandleSegv)
390b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
400b57cec5SDimitry Andric       break;
410b57cec5SDimitry Andric     case EXCEPTION_DATATYPE_MISALIGNMENT:
420b57cec5SDimitry Andric     case EXCEPTION_IN_PAGE_ERROR:
430b57cec5SDimitry Andric       if (HandlerOpt->HandleBus)
440b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
450b57cec5SDimitry Andric       break;
460b57cec5SDimitry Andric     case EXCEPTION_ILLEGAL_INSTRUCTION:
470b57cec5SDimitry Andric     case EXCEPTION_PRIV_INSTRUCTION:
480b57cec5SDimitry Andric       if (HandlerOpt->HandleIll)
490b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
500b57cec5SDimitry Andric       break;
510b57cec5SDimitry Andric     case EXCEPTION_FLT_DENORMAL_OPERAND:
520b57cec5SDimitry Andric     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
530b57cec5SDimitry Andric     case EXCEPTION_FLT_INEXACT_RESULT:
540b57cec5SDimitry Andric     case EXCEPTION_FLT_INVALID_OPERATION:
550b57cec5SDimitry Andric     case EXCEPTION_FLT_OVERFLOW:
560b57cec5SDimitry Andric     case EXCEPTION_FLT_STACK_CHECK:
570b57cec5SDimitry Andric     case EXCEPTION_FLT_UNDERFLOW:
580b57cec5SDimitry Andric     case EXCEPTION_INT_DIVIDE_BY_ZERO:
590b57cec5SDimitry Andric     case EXCEPTION_INT_OVERFLOW:
600b57cec5SDimitry Andric       if (HandlerOpt->HandleFpe)
610b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
620b57cec5SDimitry Andric       break;
630b57cec5SDimitry Andric     // TODO: handle (Options.HandleXfsz)
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric   return EXCEPTION_CONTINUE_SEARCH;
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
690b57cec5SDimitry Andric   switch (dwCtrlType) {
700b57cec5SDimitry Andric     case CTRL_C_EVENT:
710b57cec5SDimitry Andric       if (HandlerOpt->HandleInt)
720b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
730b57cec5SDimitry Andric       return TRUE;
740b57cec5SDimitry Andric     case CTRL_BREAK_EVENT:
750b57cec5SDimitry Andric       if (HandlerOpt->HandleTerm)
760b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
770b57cec5SDimitry Andric       return TRUE;
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric   return FALSE;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
830b57cec5SDimitry Andric   Fuzzer::StaticAlarmCallback();
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric class TimerQ {
870b57cec5SDimitry Andric   HANDLE TimerQueue;
880b57cec5SDimitry Andric  public:
890b57cec5SDimitry Andric   TimerQ() : TimerQueue(NULL) {}
900b57cec5SDimitry Andric   ~TimerQ() {
910b57cec5SDimitry Andric     if (TimerQueue)
920b57cec5SDimitry Andric       DeleteTimerQueueEx(TimerQueue, NULL);
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric   void SetTimer(int Seconds) {
950b57cec5SDimitry Andric     if (!TimerQueue) {
960b57cec5SDimitry Andric       TimerQueue = CreateTimerQueue();
970b57cec5SDimitry Andric       if (!TimerQueue) {
980b57cec5SDimitry Andric         Printf("libFuzzer: CreateTimerQueue failed.\n");
990b57cec5SDimitry Andric         exit(1);
1000b57cec5SDimitry Andric       }
1010b57cec5SDimitry Andric     }
1020b57cec5SDimitry Andric     HANDLE Timer;
1030b57cec5SDimitry Andric     if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
1040b57cec5SDimitry Andric         Seconds*1000, Seconds*1000, 0)) {
1050b57cec5SDimitry Andric       Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
1060b57cec5SDimitry Andric       exit(1);
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric };
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric static TimerQ Timer;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) {
1160b57cec5SDimitry Andric   HandlerOpt = &Options;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (Options.UnitTimeoutSec > 0)
1190b57cec5SDimitry Andric     Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   if (Options.HandleInt || Options.HandleTerm)
1220b57cec5SDimitry Andric     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
1230b57cec5SDimitry Andric       DWORD LastError = GetLastError();
1240b57cec5SDimitry Andric       Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
1250b57cec5SDimitry Andric         LastError);
1260b57cec5SDimitry Andric       exit(1);
1270b57cec5SDimitry Andric     }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
1300b57cec5SDimitry Andric       Options.HandleFpe)
1310b57cec5SDimitry Andric     SetUnhandledExceptionFilter(ExceptionHandler);
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (Options.HandleAbrt)
1340b57cec5SDimitry Andric     if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
1350b57cec5SDimitry Andric       Printf("libFuzzer: signal failed with %d\n", errno);
1360b57cec5SDimitry Andric       exit(1);
1370b57cec5SDimitry Andric     }
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric size_t GetPeakRSSMb() {
1450b57cec5SDimitry Andric   PROCESS_MEMORY_COUNTERS info;
1460b57cec5SDimitry Andric   if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
1470b57cec5SDimitry Andric     return 0;
1480b57cec5SDimitry Andric   return info.PeakWorkingSetSize >> 20;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) {
1520b57cec5SDimitry Andric   return _popen(Command, Mode);
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
155*5ffd83dbSDimitry Andric int CloseProcessPipe(FILE *F) {
156*5ffd83dbSDimitry Andric   return _pclose(F);
157*5ffd83dbSDimitry Andric }
158*5ffd83dbSDimitry Andric 
1590b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) {
1600b57cec5SDimitry Andric   std::string CmdLine = Cmd.toString();
1610b57cec5SDimitry Andric   return system(CmdLine.c_str());
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
164*5ffd83dbSDimitry Andric bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
165*5ffd83dbSDimitry Andric   FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
166*5ffd83dbSDimitry Andric   if (!Pipe)
167*5ffd83dbSDimitry Andric     return false;
168*5ffd83dbSDimitry Andric 
169*5ffd83dbSDimitry Andric   if (CmdOutput) {
170*5ffd83dbSDimitry Andric     char TmpBuffer[128];
171*5ffd83dbSDimitry Andric     while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
172*5ffd83dbSDimitry Andric       CmdOutput->append(TmpBuffer);
173*5ffd83dbSDimitry Andric   }
174*5ffd83dbSDimitry Andric   return _pclose(Pipe) == 0;
175*5ffd83dbSDimitry Andric }
176*5ffd83dbSDimitry Andric 
1770b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
1780b57cec5SDimitry Andric                          size_t PattLen) {
1790b57cec5SDimitry Andric   // TODO: make this implementation more efficient.
1800b57cec5SDimitry Andric   const char *Cdata = (const char *)Data;
1810b57cec5SDimitry Andric   const char *Cpatt = (const char *)Patt;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
1840b57cec5SDimitry Andric     return NULL;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   if (PattLen == 1)
1870b57cec5SDimitry Andric     return memchr(Data, *Cpatt, DataLen);
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   const char *End = Cdata + DataLen - PattLen + 1;
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric   for (const char *It = Cdata; It < End; ++It)
1920b57cec5SDimitry Andric     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
1930b57cec5SDimitry Andric       return It;
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   return NULL;
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) {
1990b57cec5SDimitry Andric   Vector<std::string> command_vector;
2000b57cec5SDimitry Andric   command_vector.push_back("dumpbin /summary > nul");
2010b57cec5SDimitry Andric   if (ExecuteCommand(Command(command_vector)) == 0)
2020b57cec5SDimitry Andric     return "dumpbin /disasm " + FileName;
2030b57cec5SDimitry Andric   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
2040b57cec5SDimitry Andric   exit(1);
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) {
2080b57cec5SDimitry Andric   return "findstr /r \"" + Regex + "\"";
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
211480093f4SDimitry Andric void DiscardOutput(int Fd) {
212480093f4SDimitry Andric   FILE* Temp = fopen("nul", "w");
213480093f4SDimitry Andric   if (!Temp)
214480093f4SDimitry Andric     return;
215480093f4SDimitry Andric   _dup2(_fileno(Temp), Fd);
216480093f4SDimitry Andric   fclose(Temp);
217480093f4SDimitry Andric }
218480093f4SDimitry Andric 
2190b57cec5SDimitry Andric } // namespace fuzzer
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS
222