forked from OSchip/llvm-project
[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:
parent
2ee3d76737
commit
e96833e648
|
|
@ -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];
|
||||
|
||||
|
|
|
|||
|
|
@ -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 == '/';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Reference in New Issue