Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.cc @@ -344,6 +344,32 @@ return true; } +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + const char *path = GetEnv("PATH"); + if (!path) + return 0; + uptr name_len = internal_strlen(name); + InternalScopedBuffer buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + static char binary_name_cache_str[kMaxPathLength]; static char process_name_cache_str[kMaxPathLength]; Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_posix.cc @@ -296,30 +296,6 @@ return GetEnv("PWD"); } -char *FindPathToBinary(const char *name) { - const char *path = GetEnv("PATH"); - if (!path) - return 0; - uptr name_len = internal_strlen(name); - InternalScopedBuffer buffer(kMaxPathLength); - const char *beg = path; - while (true) { - const char *end = internal_strchrnul(beg, ':'); - uptr prefix_len = end - beg; - if (prefix_len + name_len + 2 <= kMaxPathLength) { - internal_memcpy(buffer.data(), beg, prefix_len); - buffer[prefix_len] = '/'; - internal_memcpy(&buffer[prefix_len + 1], name, name_len); - buffer[prefix_len + 1 + name_len] = '\0'; - if (FileExists(buffer.data())) - return internal_strdup(buffer.data()); - } - if (*end == '\0') break; - beg = end + 1; - } - return 0; -} - bool IsPathSeparator(const char c) { return c == '/'; } Index: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc +++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc @@ -51,7 +51,7 @@ } bool FileExists(const char *filename) { - UNIMPLEMENTED(); + return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; } uptr internal_getpid() { @@ -292,11 +292,6 @@ UNIMPLEMENTED(); } -char *FindPathToBinary(const char *name) { - // Nothing here for now. - return 0; -} - bool IsPathSeparator(const char c) { return c == '\\' || c == '/'; } @@ -515,21 +510,32 @@ error_t *error_p) { CHECK(fd != kInvalidFd); - if (fd == kStdoutFd) { - fd = GetStdHandle(STD_OUTPUT_HANDLE); - if (fd == 0) fd = kInvalidFd; - } else if (fd == kStderrFd) { - fd = GetStdHandle(STD_ERROR_HANDLE); - if (fd == 0) fd = kInvalidFd; + // Handle null optional parameters. + error_t dummy_error; + error_p = error_p ? error_p : &dummy_error; + uptr dummy_bytes_written; + bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; + + // Initialize output parameters in case we fail. + *error_p = 0; + *bytes_written = 0; + + // Map the conventional Unix fds 1 and 2 to Windows handles. They might be + // closed, in which case this will fail. + if (fd == kStdoutFd || fd == kStderrFd) { + fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + if (fd == 0) { + *error_p = ERROR_INVALID_HANDLE; + return false; + } } - DWORD internal_bytes_written; - if (fd == kInvalidFd || - WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) { - if (error_p) *error_p = GetLastError(); + DWORD bytes_written_32; + if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { + *error_p = GetLastError(); return false; } else { - if (bytes_written) *bytes_written = internal_bytes_written; + *bytes_written = bytes_written_32; return true; } } Index: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -188,6 +188,15 @@ InternalFree(true_path); EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj")); } +#elif SANITIZER_WINDOWS +TEST(SanitizerCommon, FindPathToBinary) { + // ntdll.dll should be on PATH in all supported test environments on all + // supported Windows versions. + char *ntdll_path = FindPathToBinary("ntdll.dll"); + EXPECT_NE((char*)0, internal_strstr(ntdll_path, "ntdll.dll")); + InternalFree(ntdll_path); + EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj")); +} #endif TEST(SanitizerCommon, StripPathPrefix) { Index: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_libc_test.cc =================================================================== --- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -14,6 +14,9 @@ #include "sanitizer_common/sanitizer_platform.h" #include "gtest/gtest.h" +#if SANITIZER_WINDOWS +#include +#endif #if SANITIZER_POSIX # include # include "sanitizer_common/sanitizer_posix.h" @@ -54,6 +57,17 @@ }; static void temp_file_name(char *buf, size_t bufsize, const char *prefix) { +#if SANITIZER_WINDOWS + buf[0] = '\0'; + char tmp_dir[MAX_PATH]; + if (!::GetTempPathA(MAX_PATH, tmp_dir)) + return; + // GetTempFileNameA needs a MAX_PATH buffer. + char tmp_path[MAX_PATH]; + if (!::GetTempFileNameA(tmp_dir, prefix, 0, tmp_path)) + return; + internal_strncpy(buf, tmp_path, bufsize); +#else const char *tmpdir = "/tmp"; #if SANITIZER_ANDROID // I don't know a way to query temp directory location on Android without @@ -64,10 +78,9 @@ #endif u32 uid = GetUid(); internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid); +#endif } -// FIXME: File manipulations are not yet supported on Windows -#if SANITIZER_POSIX TEST(SanitizerCommon, FileOps) { const char *str1 = "qwerty"; uptr len1 = internal_strlen(str1); @@ -78,12 +91,20 @@ temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp."); fd_t fd = OpenFile(tmpfile, WrOnly); ASSERT_NE(fd, kInvalidFd); - EXPECT_EQ(len1, internal_write(fd, str1, len1)); - EXPECT_EQ(len2, internal_write(fd, str2, len2)); + uptr bytes_written = 0; + EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written)); + EXPECT_EQ(len1, bytes_written); + EXPECT_TRUE(WriteToFile(fd, str2, len2, &bytes_written)); + EXPECT_EQ(len2, bytes_written); CloseFile(fd); + EXPECT_TRUE(FileExists(tmpfile)); + fd = OpenFile(tmpfile, RdOnly); ASSERT_NE(fd, kInvalidFd); + +#if SANITIZER_POSIX + // The stat wrappers are posix-only. uptr fsize = internal_filesize(fd); EXPECT_EQ(len1 + len2, fsize); @@ -101,18 +122,28 @@ EXPECT_EQ(0xAB, sam.z); EXPECT_NE(0xAB, sam.st.st_size); EXPECT_NE(0, sam.st.st_size); +#endif char buf[64] = {}; - EXPECT_EQ(len1, internal_read(fd, buf, len1)); + uptr bytes_read = 0; + EXPECT_TRUE(ReadFromFile(fd, buf, len1, &bytes_read)); + EXPECT_EQ(len1, bytes_read); EXPECT_EQ(0, internal_memcmp(buf, str1, len1)); EXPECT_EQ((char)0, buf[len1 + 1]); internal_memset(buf, 0, len1); - EXPECT_EQ(len2, internal_read(fd, buf, len2)); + EXPECT_TRUE(ReadFromFile(fd, buf, len2, &bytes_read)); + EXPECT_EQ(len2, bytes_read); EXPECT_EQ(0, internal_memcmp(buf, str2, len2)); CloseFile(fd); + +#if SANITIZER_WINDOWS + // No sanitizer needs to delete a file on Windows yet. If we ever do, we can + // add a portable wrapper and test it from here. + ::DeleteFileA(&tmpfile[0]); +#else internal_unlink(tmpfile); -} #endif +} TEST(SanitizerCommon, InternalStrFunctions) { const char *haystack = "haystack";