1 //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // Misc utils implementation for Windows.
9 //===----------------------------------------------------------------------===//
10 #include "FuzzerPlatform.h"
12 #include "FuzzerCommand.h"
14 #include "FuzzerInternal.h"
23 #include <sys/types.h>
26 // These must be included after windows.h.
27 // archicture need to be set before including
29 #include <libloaderapi.h>
30 #include <stringapiset.h>
36 static const FuzzingOptions
* HandlerOpt
= nullptr;
38 static LONG CALLBACK
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo
) {
39 switch (ExceptionInfo
->ExceptionRecord
->ExceptionCode
) {
40 case EXCEPTION_ACCESS_VIOLATION
:
41 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
42 case EXCEPTION_STACK_OVERFLOW
:
43 if (HandlerOpt
->HandleSegv
)
44 Fuzzer::StaticCrashSignalCallback();
46 case EXCEPTION_DATATYPE_MISALIGNMENT
:
47 case EXCEPTION_IN_PAGE_ERROR
:
48 if (HandlerOpt
->HandleBus
)
49 Fuzzer::StaticCrashSignalCallback();
51 case EXCEPTION_ILLEGAL_INSTRUCTION
:
52 case EXCEPTION_PRIV_INSTRUCTION
:
53 if (HandlerOpt
->HandleIll
)
54 Fuzzer::StaticCrashSignalCallback();
56 case EXCEPTION_FLT_DENORMAL_OPERAND
:
57 case EXCEPTION_FLT_DIVIDE_BY_ZERO
:
58 case EXCEPTION_FLT_INEXACT_RESULT
:
59 case EXCEPTION_FLT_INVALID_OPERATION
:
60 case EXCEPTION_FLT_OVERFLOW
:
61 case EXCEPTION_FLT_STACK_CHECK
:
62 case EXCEPTION_FLT_UNDERFLOW
:
63 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
64 case EXCEPTION_INT_OVERFLOW
:
65 if (HandlerOpt
->HandleFpe
)
66 Fuzzer::StaticCrashSignalCallback();
68 // This is an undocumented exception code corresponding to a Visual C++
71 // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
73 if (HandlerOpt
->HandleWinExcept
)
74 Fuzzer::StaticCrashSignalCallback();
76 // TODO: Handle (Options.HandleXfsz)
78 return EXCEPTION_CONTINUE_SEARCH
;
81 BOOL WINAPI
CtrlHandler(DWORD dwCtrlType
) {
84 if (HandlerOpt
->HandleInt
)
85 Fuzzer::StaticInterruptCallback();
87 case CTRL_BREAK_EVENT
:
88 if (HandlerOpt
->HandleTerm
)
89 Fuzzer::StaticInterruptCallback();
95 void CALLBACK
AlarmHandler(PVOID
, BOOLEAN
) {
96 Fuzzer::StaticAlarmCallback();
102 TimerQ() : TimerQueue(NULL
) {}
105 DeleteTimerQueueEx(TimerQueue
, NULL
);
107 void SetTimer(int Seconds
) {
109 TimerQueue
= CreateTimerQueue();
111 Printf("libFuzzer: CreateTimerQueue failed.\n");
116 if (!CreateTimerQueueTimer(&Timer
, TimerQueue
, AlarmHandler
, NULL
,
117 Seconds
*1000, Seconds
*1000, 0)) {
118 Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
126 static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
128 void SetSignalHandler(const FuzzingOptions
& Options
) {
129 HandlerOpt
= &Options
;
131 if (Options
.HandleAlrm
&& Options
.UnitTimeoutSec
> 0)
132 Timer
.SetTimer(Options
.UnitTimeoutSec
/ 2 + 1);
134 if (Options
.HandleInt
|| Options
.HandleTerm
)
135 if (!SetConsoleCtrlHandler(CtrlHandler
, TRUE
)) {
136 DWORD LastError
= GetLastError();
137 Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
142 if (Options
.HandleSegv
|| Options
.HandleBus
|| Options
.HandleIll
||
143 Options
.HandleFpe
|| Options
.HandleWinExcept
)
144 SetUnhandledExceptionFilter(ExceptionHandler
);
146 if (Options
.HandleAbrt
)
147 if (SIG_ERR
== signal(SIGABRT
, CrashHandler
)) {
148 Printf("libFuzzer: signal failed with %d\n", errno
);
153 void SleepSeconds(int Seconds
) { Sleep(Seconds
* 1000); }
155 unsigned long GetPid() { return GetCurrentProcessId(); }
157 size_t GetPeakRSSMb() {
158 PROCESS_MEMORY_COUNTERS info
;
159 if (!GetProcessMemoryInfo(GetCurrentProcess(), &info
, sizeof(info
)))
161 return info
.PeakWorkingSetSize
>> 20;
164 FILE *OpenProcessPipe(const char *Command
, const char *Mode
) {
165 return _popen(Command
, Mode
);
168 int CloseProcessPipe(FILE *F
) {
172 int ExecuteCommand(const Command
&Cmd
) {
173 std::string CmdLine
= Cmd
.toString();
174 return system(CmdLine
.c_str());
177 bool ExecuteCommand(const Command
&Cmd
, std::string
*CmdOutput
) {
178 FILE *Pipe
= _popen(Cmd
.toString().c_str(), "r");
184 while (fgets(TmpBuffer
, sizeof(TmpBuffer
), Pipe
))
185 CmdOutput
->append(TmpBuffer
);
187 return _pclose(Pipe
) == 0;
190 const void *SearchMemory(const void *Data
, size_t DataLen
, const void *Patt
,
192 // TODO: make this implementation more efficient.
193 const char *Cdata
= (const char *)Data
;
194 const char *Cpatt
= (const char *)Patt
;
196 if (!Data
|| !Patt
|| DataLen
== 0 || PattLen
== 0 || DataLen
< PattLen
)
200 return memchr(Data
, *Cpatt
, DataLen
);
202 const char *End
= Cdata
+ DataLen
- PattLen
+ 1;
204 for (const char *It
= Cdata
; It
< End
; ++It
)
205 if (It
[0] == Cpatt
[0] && memcmp(It
, Cpatt
, PattLen
) == 0)
211 std::string
DisassembleCmd(const std::string
&FileName
) {
212 std::vector
<std::string
> command_vector
;
213 command_vector
.push_back("dumpbin /summary > nul");
214 if (ExecuteCommand(Command(command_vector
)) == 0)
215 return "dumpbin /disasm " + FileName
;
216 Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
220 std::string
SearchRegexCmd(const std::string
&Regex
) {
221 return "findstr /r \"" + Regex
+ "\"";
224 void DiscardOutput(int Fd
) {
225 FILE* Temp
= fopen("nul", "w");
228 _dup2(_fileno(Temp
), Fd
);
233 static size_t PageSizeCached
= []() -> size_t {
236 return si
.dwPageSize
;
238 return PageSizeCached
;
241 void SetThreadName(std::thread
&thread
, const std::string
&name
) {
243 // Not setting the thread name in MinGW environments. MinGW C++ standard
244 // libraries can either use native Windows threads or pthreads, so we
245 // don't know with certainty what kind of thread handle we're getting
246 // from thread.native_handle() here.
247 typedef HRESULT(WINAPI
* proc
)(HANDLE
, PCWSTR
);
248 HMODULE kbase
= GetModuleHandleA("KernelBase.dll");
249 proc ThreadNameProc
= reinterpret_cast<proc
>(
250 (void *)GetProcAddress(kbase
, "SetThreadDescription"));
251 if (ThreadNameProc
) {
253 auto sz
= MultiByteToWideChar(CP_UTF8
, 0, name
.data(), -1, nullptr, 0);
256 if (MultiByteToWideChar(CP_UTF8
, 0, name
.data(), -1, &buf
[0], sz
) > 0) {
257 (void)ThreadNameProc(thread
.native_handle(), buf
.c_str());
264 } // namespace fuzzer
266 #endif // LIBFUZZER_WINDOWS