1717
1818#include " ./centipede/util.h"
1919
20+ #if defined(_WIN32)
21+ #include " ./centipede/windows_includes.h"
22+ #else
2023#include < sys/mman.h>
2124#include < unistd.h>
25+ #endif
2226
2327#include < algorithm>
2428#include < cctype>
4751#include " absl/base/const_init.h"
4852#include " absl/base/nullability.h"
4953#include " absl/base/thread_annotations.h"
54+ #include " absl/strings/match.h"
5055#include " absl/strings/str_format.h"
5156#include " absl/strings/str_replace.h"
5257#include " absl/strings/str_split.h"
@@ -63,8 +68,13 @@ namespace fuzztest::internal {
6368
6469size_t GetRandomSeed (size_t seed) {
6570 if (seed != 0 ) return seed;
71+ #if defined(_WIN32)
72+ return time (nullptr ) + GetCurrentProcessId () +
73+ std::hash<std::thread::id>{}(std::this_thread::get_id ());
74+ #else
6675 return time (nullptr ) + getpid () +
6776 std::hash<std::thread::id>{}(std::this_thread::get_id ());
77+ #endif
6878}
6979
7080std::string AsPrintableString (ByteSpan data, size_t max_len) {
@@ -83,7 +93,7 @@ std::string AsPrintableString(ByteSpan data, size_t max_len) {
8393
8494template <typename Container>
8595void ReadFromLocalFile (std::string_view file_path, Container &data) {
86- std::ifstream f (std::string{file_path});
96+ std::ifstream f (std::string{file_path}, std::ios::in | std::ios::binary );
8797 if (!f) return ;
8898 f.seekg (0 , std::ios_base::end);
8999 auto size = f.tellg ();
@@ -112,12 +122,13 @@ void ReadFromLocalFile(std::string_view file_path,
112122}
113123
114124void ClearLocalFileContents (std::string_view file_path) {
115- std::ofstream f (std::string{file_path}, std::ios::out | std::ios::trunc);
125+ std::ofstream f (std::string{file_path},
126+ std::ios::out | std::ios::trunc | std::ios::binary);
116127 FUZZTEST_CHECK (f) << " Failed to clear the file: " << file_path;
117128}
118129
119130void WriteToLocalFile (std::string_view file_path, ByteSpan data) {
120- std::ofstream f (std::string{file_path});
131+ std::ofstream f (std::string{file_path}, std::ios::out | std::ios::binary );
121132 FUZZTEST_CHECK (f) << " Failed to open local file: " << file_path;
122133 f.write (reinterpret_cast <const char *>(data.data ()),
123134 static_cast <int64_t >(data.size ()));
@@ -136,13 +147,15 @@ void WriteToLocalFile(std::string_view file_path, const FeatureVec &data) {
136147
137148void WriteToLocalHashedFileInDir (std::string_view dir_path, ByteSpan data) {
138149 if (dir_path.empty ()) return ;
139- std::string file_path = std::filesystem::path (dir_path).append (Hash (data));
150+ std::string file_path =
151+ std::filesystem::path (dir_path).append (Hash (data)).string ();
140152 WriteToLocalFile (file_path, data);
141153}
142154
143155void WriteToRemoteHashedFileInDir (std::string_view dir_path, ByteSpan data) {
144156 if (dir_path.empty ()) return ;
145- std::string file_path = std::filesystem::path (dir_path).append (Hash (data));
157+ std::string file_path =
158+ std::filesystem::path (dir_path).append (Hash (data)).string ();
146159 FUZZTEST_CHECK_OK (
147160 RemoteFileSetContents (file_path, std::string (data.begin (), data.end ())));
148161}
@@ -155,17 +168,24 @@ std::string HashOfFileContents(std::string_view file_path) {
155168}
156169
157170std::string ProcessAndThreadUniqueID (std::string_view prefix) {
158- // operator << is the only way to serialize std::this_thread::get_id().
159171 std::ostringstream oss;
172+ #if defined(_WIN32)
173+ oss << prefix << GetCurrentProcessId () << " -" << GetCurrentThreadId ();
174+ #else
175+ // operator << is the only way to serialize std::this_thread::get_id().
160176 oss << prefix << getpid () << " -" << std::this_thread::get_id ();
177+ #endif
161178 return oss.str ();
162179}
163180
164181std::string TemporaryLocalDirPath () {
165182 const char *TMPDIR = getenv (" TMPDIR" );
183+ if (!TMPDIR ) TMPDIR = getenv (" TEMP" );
184+ if (!TMPDIR ) TMPDIR = getenv (" TMP" );
166185 std::string tmp = TMPDIR ? TMPDIR : " /tmp" ;
167- return std::filesystem::path (tmp).append (
168- ProcessAndThreadUniqueID (" centipede-" ));
186+ return std::filesystem::path (tmp)
187+ .append (ProcessAndThreadUniqueID (" centipede-" ))
188+ .string ();
169189}
170190
171191// We need to maintain a global set of dirs that CreateLocalDirRemovedAtExit()
@@ -189,13 +209,15 @@ static void RemoveDirsAtExit() {
189209
190210void CreateLocalDirRemovedAtExit (std::string_view path) {
191211 // Safeguard against removing dirs not created by TemporaryLocalDirPath().
192- FUZZTEST_CHECK_NE (path.find (" /centipede-" ), std::string::npos);
212+ FUZZTEST_CHECK (absl::StrContains (path, " /centipede-" ) ||
213+ absl::StrContains (path, " \\ centipede-" ));
193214 // Create the dir.
194215 std::error_code error;
195- std::filesystem::remove_all (path, error);
196- FUZZTEST_LOG_IF (ERROR , error)
197- << " Unable to clean up existing dir " << path << " : " << error.message ();
198- std::filesystem::create_directories (path);
216+ std::filesystem::path p (path);
217+ if (std::filesystem::exists (p, error)) {
218+ std::filesystem::remove_all (p, error);
219+ }
220+ std::filesystem::create_directories (p, error);
199221 // Add to dirs_to_delete_at_exit.
200222 absl::MutexLock lock (dirs_to_delete_at_exit_mutex);
201223 if (!dirs_to_delete_at_exit) {
@@ -206,7 +228,7 @@ void CreateLocalDirRemovedAtExit(std::string_view path) {
206228}
207229
208230ScopedFile::ScopedFile (std::string_view dir_path, std::string_view name)
209- : my_path_(std::filesystem::path(dir_path) / name) {}
231+ : my_path_(( std::filesystem::path(dir_path) / name).string() ) {}
210232
211233ScopedFile::~ScopedFile () {
212234 std::error_code error;
@@ -359,16 +381,53 @@ std::vector<size_t> RandomWeightedSubset(absl::Span<const uint64_t> set,
359381 return res;
360382}
361383
384+ #if defined(_WIN32)
385+ static LONG CALLBACK
386+ AutoCommitPageFaultHandler (PEXCEPTION_POINTERS ExceptionInfo) {
387+ if (ExceptionInfo->ExceptionRecord ->ExceptionCode ==
388+ EXCEPTION_ACCESS_VIOLATION ) {
389+ ULONG_PTR fault_addr =
390+ ExceptionInfo->ExceptionRecord ->ExceptionInformation [1 ];
391+ if (VirtualAlloc (reinterpret_cast <void *>(fault_addr), 1 , MEM_COMMIT ,
392+ PAGE_READWRITE ) != nullptr ) {
393+ return EXCEPTION_CONTINUE_EXECUTION ;
394+ }
395+ }
396+ return EXCEPTION_CONTINUE_SEARCH ;
397+ }
398+ #endif
399+
362400uint8_t *MmapNoReserve (size_t size) {
401+ #if defined(_WIN32)
402+ // Set up page fault handler to commit page on demand.
403+ static bool installed_veh = []() {
404+ // Must use `First=0` as it could otherwise conflict with e.g. sanitizers.
405+ AddVectoredExceptionHandler (/* First=*/ 0 , AutoCommitPageFaultHandler);
406+ return true ;
407+ }();
408+ (void )installed_veh;
409+ // MEM_RESERVE has different semantics and does not contradict with
410+ // MAP_NORESERVE for mmap.
411+ auto result = VirtualAlloc (nullptr , size, MEM_RESERVE , PAGE_READWRITE );
412+ FUZZTEST_CHECK (result != nullptr )
413+ << " VirtualAlloc failed for size " << size << " err=" << GetLastError ();
414+ return reinterpret_cast <uint8_t *>(result);
415+ #else
363416 auto result = mmap (0 , size, PROT_READ | PROT_WRITE ,
364417 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE , -1 , 0 );
365418 FUZZTEST_CHECK (result != MAP_FAILED );
366419 return reinterpret_cast <uint8_t *>(result);
420+ #endif
367421}
368422
369423void Munmap (uint8_t *ptr, size_t size) {
424+ #if defined(_WIN32)
425+ BOOL result = VirtualFree (ptr, 0 , MEM_RELEASE );
426+ FUZZTEST_CHECK (result != 0 );
427+ #else
370428 auto result = munmap (ptr, size);
371429 FUZZTEST_CHECK_EQ (result, 0 );
430+ #endif
372431}
373432
374433int PollTimeoutMs (absl::Duration timeout) {
0 commit comments