[Windows] Implement FileExists, ReadFromFile, and FindPathToBinary

Summary: These are needed to talk to llvm-symbolizer on Windows.

Reviewers: samsonov

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D11920

llvm-svn: 244533
This commit is contained in:
Reid Kleckner 2015-08-10 23:40:27 +00:00
parent 2ee3d76737
commit e96833e648
5 changed files with 96 additions and 48 deletions

View File

@ -344,6 +344,32 @@ bool TemplateMatch(const char *templ, const char *str) {
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<char> 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];

View File

@ -296,30 +296,6 @@ const char *GetPwd() {
return GetEnv("PWD");
}
char *FindPathToBinary(const char *name) {
const char *path = GetEnv("PATH");
if (!path)
return 0;
uptr name_len = internal_strlen(name);
InternalScopedBuffer<char> 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 == '/';
}

View File

@ -51,7 +51,7 @@ uptr GetMaxVirtualAddress() {
}
bool FileExists(const char *filename) {
UNIMPLEMENTED();
return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES;
}
uptr internal_getpid() {
@ -292,11 +292,6 @@ void SetAddressSpaceUnlimited() {
UNIMPLEMENTED();
}
char *FindPathToBinary(const char *name) {
// Nothing here for now.
return 0;
}
bool IsPathSeparator(const char c) {
return c == '\\' || c == '/';
}
@ -515,21 +510,32 @@ bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
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;
}
}

View File

@ -188,6 +188,15 @@ TEST(SanitizerCommon, FindPathToBinary) {
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) {

View File

@ -14,6 +14,9 @@
#include "sanitizer_common/sanitizer_platform.h"
#include "gtest/gtest.h"
#if SANITIZER_WINDOWS
#include <windows.h>
#endif
#if SANITIZER_POSIX
# include <sys/stat.h>
# include "sanitizer_common/sanitizer_posix.h"
@ -54,6 +57,17 @@ struct stat_and_more {
};
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 @@ static void temp_file_name(char *buf, size_t bufsize, const char *prefix) {
#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 @@ TEST(SanitizerCommon, FileOps) {
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 @@ TEST(SanitizerCommon, FileOps) {
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";