From 517118e6b46e7fe5bae4b17e61b47e8eedc1856f Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 7 May 2013 12:47:04 +0000 Subject: [PATCH] [sanitizer] Sanitizer __internal_*stat interface. With this change, __internal_*stat always expect a "struct stat *" argument. This avoids stat/stat64 caller-side confusion (sanitizer_common tests already made this mistake), and allows the use of __internal_fstat() as a drop-in replacement for libc's fstat(). llvm-svn: 181311 --- .../lib/sanitizer_common/sanitizer_linux.cc | 47 +++++++++++++------ .../tests/sanitizer_libc_test.cc | 15 ++++++ 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index ef185571ada1..194c6a80e6ba 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -108,11 +108,34 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) { return res; } +#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS +static void stat64_to_stat(struct stat64 *in, struct stat *out) { + internal_memset(out, 0, sizeof(*out)); + out->st_dev = in->st_dev; + out->st_ino = in->st_ino; + out->st_mode = in->st_mode; + out->st_nlink = in->st_nlink; + out->st_uid = in->st_uid; + out->st_gid = in->st_gid; + out->st_rdev = in->st_rdev; + out->st_size = in->st_size; + out->st_blksize = in->st_blksize; + out->st_blocks = in->st_blocks; + out->st_atime = in->st_atime; + out->st_mtime = in->st_mtime; + out->st_ctime = in->st_ctime; + out->st_ino = in->st_ino; +} +#endif + int internal_stat(const char *path, void *buf) { #if SANITIZER_LINUX_USES_64BIT_SYSCALLS return syscall(__NR_stat, path, buf); #else - return syscall(__NR_stat64, path, buf); + struct stat64 buf64; + int res = syscall(__NR_stat64, path, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; #endif } @@ -120,7 +143,10 @@ int internal_lstat(const char *path, void *buf) { #if SANITIZER_LINUX_USES_64BIT_SYSCALLS return syscall(__NR_lstat, path, buf); #else - return syscall(__NR_lstat64, path, buf); + struct stat64 buf64; + int res = syscall(__NR_lstat64, path, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; #endif } @@ -128,16 +154,15 @@ int internal_fstat(fd_t fd, void *buf) { #if SANITIZER_LINUX_USES_64BIT_SYSCALLS return syscall(__NR_fstat, fd, buf); #else - return syscall(__NR_fstat64, fd, buf); + struct stat64 buf64; + int res = syscall(__NR_fstat64, fd, &buf64); + stat64_to_stat(&buf64, (struct stat *)buf); + return res; #endif } uptr internal_filesize(fd_t fd) { -#if SANITIZER_LINUX_USES_64BIT_SYSCALLS struct stat st; -#else - struct stat64 st; -#endif if (internal_fstat(fd, &st)) return -1; return (uptr)st.st_size; @@ -166,15 +191,9 @@ void internal__exit(int exitcode) { // ----------------- sanitizer_common.h bool FileExists(const char *filename) { -#if SANITIZER_LINUX_USES_64BIT_SYSCALLS struct stat st; - if (syscall(__NR_stat, filename, &st)) + if (internal_stat(filename, &st)) return false; -#else - struct stat64 st; - if (syscall(__NR_stat64, filename, &st)) - return false; -#endif // Sanity check: filename is a regular file. return S_ISREG(st.st_mode); } diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc index b677130826bb..51cd66cf0cd4 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -49,6 +49,11 @@ TEST(SanitizerCommon, mem_is_zero) { delete [] x; } +struct stat_and_more { + struct stat st; + unsigned char z; +}; + TEST(SanitizerCommon, FileOps) { const char *str1 = "qwerty"; uptr len1 = internal_strlen(str1); @@ -86,6 +91,15 @@ TEST(SanitizerCommon, FileOps) { EXPECT_EQ(0, internal_lstat(temp_filename, &st2)); EXPECT_EQ(0, internal_fstat(fd, &st3)); EXPECT_EQ(fsize, (uptr)st3.st_size); + + // Verify that internal_fstat does not write beyond the end of the supplied + // buffer. + struct stat_and_more sam; + memset(&sam, 0xAB, sizeof(sam)); + EXPECT_EQ(0, internal_fstat(fd, &sam.st)); + EXPECT_EQ(0xAB, sam.z); + EXPECT_NE(0xAB, sam.st.st_size); + EXPECT_NE(0, sam.st.st_size); #endif char buf[64] = {}; @@ -97,3 +111,4 @@ TEST(SanitizerCommon, FileOps) { EXPECT_EQ(0, internal_memcmp(buf, str2, len2)); internal_close(fd); } +