xref: /freebsd/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
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 //===----------------------------------------------------------------------===//
100b57cec5SDimitry Andric #include "FuzzerDefs.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>
19*480093f4SDimitry 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 
1550b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) {
1560b57cec5SDimitry Andric   std::string CmdLine = Cmd.toString();
1570b57cec5SDimitry Andric   return system(CmdLine.c_str());
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
1610b57cec5SDimitry Andric                          size_t PattLen) {
1620b57cec5SDimitry Andric   // TODO: make this implementation more efficient.
1630b57cec5SDimitry Andric   const char *Cdata = (const char *)Data;
1640b57cec5SDimitry Andric   const char *Cpatt = (const char *)Patt;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
1670b57cec5SDimitry Andric     return NULL;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   if (PattLen == 1)
1700b57cec5SDimitry Andric     return memchr(Data, *Cpatt, DataLen);
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   const char *End = Cdata + DataLen - PattLen + 1;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   for (const char *It = Cdata; It < End; ++It)
1750b57cec5SDimitry Andric     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
1760b57cec5SDimitry Andric       return It;
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   return NULL;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) {
1820b57cec5SDimitry Andric   Vector<std::string> command_vector;
1830b57cec5SDimitry Andric   command_vector.push_back("dumpbin /summary > nul");
1840b57cec5SDimitry Andric   if (ExecuteCommand(Command(command_vector)) == 0)
1850b57cec5SDimitry Andric     return "dumpbin /disasm " + FileName;
1860b57cec5SDimitry Andric   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
1870b57cec5SDimitry Andric   exit(1);
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) {
1910b57cec5SDimitry Andric   return "findstr /r \"" + Regex + "\"";
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
194*480093f4SDimitry Andric void DiscardOutput(int Fd) {
195*480093f4SDimitry Andric   FILE* Temp = fopen("nul", "w");
196*480093f4SDimitry Andric   if (!Temp)
197*480093f4SDimitry Andric     return;
198*480093f4SDimitry Andric   _dup2(_fileno(Temp), Fd);
199*480093f4SDimitry Andric   fclose(Temp);
200*480093f4SDimitry Andric }
201*480093f4SDimitry Andric 
2020b57cec5SDimitry Andric } // namespace fuzzer
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS
205