xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp (revision 415efcecd8b80f68e76376ef2b854cb6f5c84b5a)
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 //===----------------------------------------------------------------------===//
105ffd83dbSDimitry 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>
240fca6ea1SDimitry Andric // clang-format off
250b57cec5SDimitry Andric #include <windows.h>
260fca6ea1SDimitry Andric // These must be included after windows.h.
270fca6ea1SDimitry Andric // archicture need to be set before including
280fca6ea1SDimitry Andric // libloaderapi
290fca6ea1SDimitry Andric #include <libloaderapi.h>
300fca6ea1SDimitry Andric #include <stringapiset.h>
310b57cec5SDimitry Andric #include <psapi.h>
320fca6ea1SDimitry Andric // clang-format on
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric namespace fuzzer {
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
390b57cec5SDimitry Andric   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
400b57cec5SDimitry Andric     case EXCEPTION_ACCESS_VIOLATION:
410b57cec5SDimitry Andric     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
420b57cec5SDimitry Andric     case EXCEPTION_STACK_OVERFLOW:
430b57cec5SDimitry Andric       if (HandlerOpt->HandleSegv)
440b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
450b57cec5SDimitry Andric       break;
460b57cec5SDimitry Andric     case EXCEPTION_DATATYPE_MISALIGNMENT:
470b57cec5SDimitry Andric     case EXCEPTION_IN_PAGE_ERROR:
480b57cec5SDimitry Andric       if (HandlerOpt->HandleBus)
490b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
500b57cec5SDimitry Andric       break;
510b57cec5SDimitry Andric     case EXCEPTION_ILLEGAL_INSTRUCTION:
520b57cec5SDimitry Andric     case EXCEPTION_PRIV_INSTRUCTION:
530b57cec5SDimitry Andric       if (HandlerOpt->HandleIll)
540b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
550b57cec5SDimitry Andric       break;
560b57cec5SDimitry Andric     case EXCEPTION_FLT_DENORMAL_OPERAND:
570b57cec5SDimitry Andric     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
580b57cec5SDimitry Andric     case EXCEPTION_FLT_INEXACT_RESULT:
590b57cec5SDimitry Andric     case EXCEPTION_FLT_INVALID_OPERATION:
600b57cec5SDimitry Andric     case EXCEPTION_FLT_OVERFLOW:
610b57cec5SDimitry Andric     case EXCEPTION_FLT_STACK_CHECK:
620b57cec5SDimitry Andric     case EXCEPTION_FLT_UNDERFLOW:
630b57cec5SDimitry Andric     case EXCEPTION_INT_DIVIDE_BY_ZERO:
640b57cec5SDimitry Andric     case EXCEPTION_INT_OVERFLOW:
650b57cec5SDimitry Andric       if (HandlerOpt->HandleFpe)
660b57cec5SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
670b57cec5SDimitry Andric       break;
68e8d8bef9SDimitry Andric     // This is an undocumented exception code corresponding to a Visual C++
69e8d8bef9SDimitry Andric     // Exception.
70e8d8bef9SDimitry Andric     //
71e8d8bef9SDimitry Andric     // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
72e8d8bef9SDimitry Andric     case 0xE06D7363:
73e8d8bef9SDimitry Andric       if (HandlerOpt->HandleWinExcept)
74e8d8bef9SDimitry Andric         Fuzzer::StaticCrashSignalCallback();
75e8d8bef9SDimitry Andric       break;
76e8d8bef9SDimitry Andric       // TODO: Handle (Options.HandleXfsz)
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric   return EXCEPTION_CONTINUE_SEARCH;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
820b57cec5SDimitry Andric   switch (dwCtrlType) {
830b57cec5SDimitry Andric     case CTRL_C_EVENT:
840b57cec5SDimitry Andric       if (HandlerOpt->HandleInt)
850b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
860b57cec5SDimitry Andric       return TRUE;
870b57cec5SDimitry Andric     case CTRL_BREAK_EVENT:
880b57cec5SDimitry Andric       if (HandlerOpt->HandleTerm)
890b57cec5SDimitry Andric         Fuzzer::StaticInterruptCallback();
900b57cec5SDimitry Andric       return TRUE;
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric   return FALSE;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
960b57cec5SDimitry Andric   Fuzzer::StaticAlarmCallback();
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric class TimerQ {
1000b57cec5SDimitry Andric   HANDLE TimerQueue;
1010b57cec5SDimitry Andric  public:
1020b57cec5SDimitry Andric   TimerQ() : TimerQueue(NULL) {}
1030b57cec5SDimitry Andric   ~TimerQ() {
1040b57cec5SDimitry Andric     if (TimerQueue)
1050b57cec5SDimitry Andric       DeleteTimerQueueEx(TimerQueue, NULL);
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric   void SetTimer(int Seconds) {
1080b57cec5SDimitry Andric     if (!TimerQueue) {
1090b57cec5SDimitry Andric       TimerQueue = CreateTimerQueue();
1100b57cec5SDimitry Andric       if (!TimerQueue) {
1110b57cec5SDimitry Andric         Printf("libFuzzer: CreateTimerQueue failed.\n");
1120b57cec5SDimitry Andric         exit(1);
1130b57cec5SDimitry Andric       }
1140b57cec5SDimitry Andric     }
1150b57cec5SDimitry Andric     HANDLE Timer;
1160b57cec5SDimitry Andric     if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
1170b57cec5SDimitry Andric         Seconds*1000, Seconds*1000, 0)) {
1180b57cec5SDimitry Andric       Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
1190b57cec5SDimitry Andric       exit(1);
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric };
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric static TimerQ Timer;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) {
1290b57cec5SDimitry Andric   HandlerOpt = &Options;
1300b57cec5SDimitry Andric 
131e8d8bef9SDimitry Andric   if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
1320b57cec5SDimitry Andric     Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   if (Options.HandleInt || Options.HandleTerm)
1350b57cec5SDimitry Andric     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
1360b57cec5SDimitry Andric       DWORD LastError = GetLastError();
1370b57cec5SDimitry Andric       Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
1380b57cec5SDimitry Andric         LastError);
1390b57cec5SDimitry Andric       exit(1);
1400b57cec5SDimitry Andric     }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
143e8d8bef9SDimitry Andric       Options.HandleFpe || Options.HandleWinExcept)
1440b57cec5SDimitry Andric     SetUnhandledExceptionFilter(ExceptionHandler);
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   if (Options.HandleAbrt)
1470b57cec5SDimitry Andric     if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
1480b57cec5SDimitry Andric       Printf("libFuzzer: signal failed with %d\n", errno);
1490b57cec5SDimitry Andric       exit(1);
1500b57cec5SDimitry Andric     }
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric size_t GetPeakRSSMb() {
1580b57cec5SDimitry Andric   PROCESS_MEMORY_COUNTERS info;
1590b57cec5SDimitry Andric   if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
1600b57cec5SDimitry Andric     return 0;
1610b57cec5SDimitry Andric   return info.PeakWorkingSetSize >> 20;
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) {
1650b57cec5SDimitry Andric   return _popen(Command, Mode);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1685ffd83dbSDimitry Andric int CloseProcessPipe(FILE *F) {
1695ffd83dbSDimitry Andric   return _pclose(F);
1705ffd83dbSDimitry Andric }
1715ffd83dbSDimitry Andric 
1720b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) {
1730b57cec5SDimitry Andric   std::string CmdLine = Cmd.toString();
1740b57cec5SDimitry Andric   return system(CmdLine.c_str());
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
1775ffd83dbSDimitry Andric bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
1785ffd83dbSDimitry Andric   FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
1795ffd83dbSDimitry Andric   if (!Pipe)
1805ffd83dbSDimitry Andric     return false;
1815ffd83dbSDimitry Andric 
1825ffd83dbSDimitry Andric   if (CmdOutput) {
1835ffd83dbSDimitry Andric     char TmpBuffer[128];
1845ffd83dbSDimitry Andric     while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
1855ffd83dbSDimitry Andric       CmdOutput->append(TmpBuffer);
1865ffd83dbSDimitry Andric   }
1875ffd83dbSDimitry Andric   return _pclose(Pipe) == 0;
1885ffd83dbSDimitry Andric }
1895ffd83dbSDimitry Andric 
1900b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
1910b57cec5SDimitry Andric                          size_t PattLen) {
1920b57cec5SDimitry Andric   // TODO: make this implementation more efficient.
1930b57cec5SDimitry Andric   const char *Cdata = (const char *)Data;
1940b57cec5SDimitry Andric   const char *Cpatt = (const char *)Patt;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
1970b57cec5SDimitry Andric     return NULL;
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   if (PattLen == 1)
2000b57cec5SDimitry Andric     return memchr(Data, *Cpatt, DataLen);
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   const char *End = Cdata + DataLen - PattLen + 1;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   for (const char *It = Cdata; It < End; ++It)
2050b57cec5SDimitry Andric     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
2060b57cec5SDimitry Andric       return It;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   return NULL;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) {
212349cc55cSDimitry Andric   std::vector<std::string> command_vector;
2130b57cec5SDimitry Andric   command_vector.push_back("dumpbin /summary > nul");
2140b57cec5SDimitry Andric   if (ExecuteCommand(Command(command_vector)) == 0)
2150b57cec5SDimitry Andric     return "dumpbin /disasm " + FileName;
2160b57cec5SDimitry Andric   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
2170b57cec5SDimitry Andric   exit(1);
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) {
2210b57cec5SDimitry Andric   return "findstr /r \"" + Regex + "\"";
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
224480093f4SDimitry Andric void DiscardOutput(int Fd) {
225480093f4SDimitry Andric   FILE* Temp = fopen("nul", "w");
226480093f4SDimitry Andric   if (!Temp)
227480093f4SDimitry Andric     return;
228480093f4SDimitry Andric   _dup2(_fileno(Temp), Fd);
229480093f4SDimitry Andric   fclose(Temp);
230480093f4SDimitry Andric }
231480093f4SDimitry Andric 
23206c3fb27SDimitry Andric size_t PageSize() {
23306c3fb27SDimitry Andric   static size_t PageSizeCached = []() -> size_t {
23406c3fb27SDimitry Andric     SYSTEM_INFO si;
23506c3fb27SDimitry Andric     GetSystemInfo(&si);
23606c3fb27SDimitry Andric     return si.dwPageSize;
23706c3fb27SDimitry Andric   }();
23806c3fb27SDimitry Andric   return PageSizeCached;
23906c3fb27SDimitry Andric }
24006c3fb27SDimitry Andric 
2415f757f3fSDimitry Andric void SetThreadName(std::thread &thread, const std::string &name) {
242*415efcecSDimitry Andric #ifndef __MINGW32__
243*415efcecSDimitry Andric   // Not setting the thread name in MinGW environments. MinGW C++ standard
244*415efcecSDimitry Andric   // libraries can either use native Windows threads or pthreads, so we
245*415efcecSDimitry Andric   // don't know with certainty what kind of thread handle we're getting
246*415efcecSDimitry Andric   // from thread.native_handle() here.
2470fca6ea1SDimitry Andric   typedef HRESULT(WINAPI * proc)(HANDLE, PCWSTR);
2480fca6ea1SDimitry Andric   HMODULE kbase = GetModuleHandleA("KernelBase.dll");
2490fca6ea1SDimitry Andric   proc ThreadNameProc =
2500fca6ea1SDimitry Andric       reinterpret_cast<proc>(GetProcAddress(kbase, "SetThreadDescription"));
2510fca6ea1SDimitry Andric   if (ThreadNameProc) {
2520fca6ea1SDimitry Andric     std::wstring buf;
2530fca6ea1SDimitry Andric     auto sz = MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, nullptr, 0);
2540fca6ea1SDimitry Andric     if (sz > 0) {
2550fca6ea1SDimitry Andric       buf.resize(sz);
2560fca6ea1SDimitry Andric       if (MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, &buf[0], sz) > 0) {
2570fca6ea1SDimitry Andric         (void)ThreadNameProc(thread.native_handle(), buf.c_str());
2580fca6ea1SDimitry Andric       }
2590fca6ea1SDimitry Andric     }
2600fca6ea1SDimitry Andric   }
2615deeebd8SDimitry Andric #endif
2625f757f3fSDimitry Andric }
2635f757f3fSDimitry Andric 
2640b57cec5SDimitry Andric } // namespace fuzzer
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS
267