-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[rtsan][compiler-rt] Add 64 bit file interceptors, test for _FILE_OFFSET_BITS #108057
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-compiler-rt-sanitizer Author: Chris Apple (cjappl) ChangesFrom #107988 We were not intercepting the 64 bit versions of these calls, leading to tests failing when _FILE_OFFSET_BITS = 64. Add the appropriate interceptors, and add tests for them Full diff: https://github.com/llvm/llvm-project/pull/108057.diff 4 Files Affected:
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
index 409e27c3ad3234..344c753d8fe706 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
@@ -73,6 +73,25 @@ INTERCEPTOR(int, open, const char *path, int oflag, ...) {
return result;
}
+#if SANITIZER_INTERCEPT_OPEN64
+INTERCEPTOR(int, open64, const char *path, int oflag, ...) {
+ // TODO Establish whether we should intercept here if the flag contains
+ // O_NONBLOCK
+ __rtsan_expect_not_realtime("open64");
+
+ va_list args;
+ va_start(args, oflag);
+ const mode_t mode = va_arg(args, int);
+ va_end(args);
+
+ const int result = REAL(open64)(path, oflag, mode);
+ return result;
+}
+#define RTSAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_OPEN64
+#endif // SANITIZER_INTERCEPT_OPEN64
+
INTERCEPTOR(int, openat, int fd, const char *path, int oflag, ...) {
// TODO Establish whether we should intercept here if the flag contains
// O_NONBLOCK
@@ -87,6 +106,25 @@ INTERCEPTOR(int, openat, int fd, const char *path, int oflag, ...) {
return result;
}
+#if SANITIZER_INTERCEPT_OPENAT64
+INTERCEPTOR(int, openat64, int fd, const char *path, int oflag, ...) {
+ // TODO Establish whether we should intercept here if the flag contains
+ // O_NONBLOCK
+ __rtsan_expect_not_realtime("openat64");
+
+ va_list args;
+ va_start(args, oflag);
+ mode_t mode = va_arg(args, int);
+ va_end(args);
+
+ const int result = REAL(openat64)(fd, path, oflag, mode);
+ return result;
+}
+#define RTSAN_MAYBE_INTERCEPT_OPENAT64 INTERCEPT_FUNCTION(openat64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_OPENAT64
+#endif // SANITIZER_INTERCEPT_OPENAT64
+
INTERCEPTOR(int, creat, const char *path, mode_t mode) {
// TODO Establish whether we should intercept here if the flag contains
// O_NONBLOCK
@@ -95,6 +133,19 @@ INTERCEPTOR(int, creat, const char *path, mode_t mode) {
return result;
}
+#if SANITIZER_INTERCEPT_CREAT64
+INTERCEPTOR(int, creat64, const char *path, mode_t mode) {
+ // TODO Establish whether we should intercept here if the flag contains
+ // O_NONBLOCK
+ __rtsan_expect_not_realtime("creat64");
+ const int result = REAL(creat64)(path, mode);
+ return result;
+}
+#define RTSAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_CREAT64
+#endif // SANITIZER_INTERCEPT_CREAT64
+
INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) {
__rtsan_expect_not_realtime("fcntl");
@@ -116,6 +167,32 @@ INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) {
return result;
}
+#if SANITIZER_INTERCEPT_FCNTL64
+INTERCEPTOR(int, fcntl64, int filedes, int cmd, ...) {
+ __rtsan_expect_not_realtime("fcntl64");
+
+ va_list args;
+ va_start(args, cmd);
+
+ // Following precedent here. The linux source (fcntl.c, do_fcntl) accepts the
+ // final argument in a variable that will hold the largest of the possible
+ // argument types (pointers and ints are typical in fcntl) It is then assumed
+ // that the implementation of fcntl will cast it properly depending on cmd.
+ //
+ // This is also similar to what is done in
+ // sanitizer_common/sanitizer_common_syscalls.inc
+ const unsigned long arg = va_arg(args, unsigned long);
+ int result = REAL(fcntl64)(filedes, cmd, arg);
+
+ va_end(args);
+
+ return result;
+}
+#define RTSAN_MAYBE_INTERCEPT_FCNTL64 INTERCEPT_FUNCTION(fcntl64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_FCNTL64
+#endif // SANITIZER_INTERCEPT_FCNTL64
+
INTERCEPTOR(int, close, int filedes) {
__rtsan_expect_not_realtime("close");
return REAL(close)(filedes);
@@ -126,6 +203,16 @@ INTERCEPTOR(FILE *, fopen, const char *path, const char *mode) {
return REAL(fopen)(path, mode);
}
+#if SANITIZER_INTERCEPT_FOPEN64
+INTERCEPTOR(FILE *, fopen64, const char *path, const char *mode) {
+ __rtsan_expect_not_realtime("fopen64");
+ return REAL(fopen64)(path, mode);
+}
+#define RTSAN_MAYBE_INTERCEPT_FOPEN64 INTERCEPT_FUNCTION(fopen64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_FOPEN64
+#endif // SANITIZER_INTERCEPT_FOPEN64
+
INTERCEPTOR(size_t, fread, void *ptr, size_t size, size_t nitems,
FILE *stream) {
__rtsan_expect_not_realtime("fread");
@@ -169,6 +256,16 @@ INTERCEPTOR(ssize_t, pread, int fd, void *buf, size_t count, off_t offset) {
return REAL(pread)(fd, buf, count, offset);
}
+#if SANITIZER_INTERCEPT_PREAD64
+INTERCEPTOR(ssize_t, pread64, int fd, void *buf, size_t count, off_t offset) {
+ __rtsan_expect_not_realtime("pread64");
+ return REAL(pread64)(fd, buf, count, offset);
+}
+#define RTSAN_MAYBE_INTERCEPT_PREAD64 INTERCEPT_FUNCTION(pread64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_PREAD64
+#endif // SANITIZER_INTERCEPT_PREAD64
+
INTERCEPTOR(ssize_t, readv, int fd, const struct iovec *iov, int iovcnt) {
__rtsan_expect_not_realtime("readv");
return REAL(readv)(fd, iov, iovcnt);
@@ -180,6 +277,17 @@ INTERCEPTOR(ssize_t, pwrite, int fd, const void *buf, size_t count,
return REAL(pwrite)(fd, buf, count, offset);
}
+#if SANITIZER_INTERCEPT_PWRITE64
+INTERCEPTOR(ssize_t, pwrite64, int fd, const void *buf, size_t count,
+ off_t offset) {
+ __rtsan_expect_not_realtime("pwrite64");
+ return REAL(pwrite64)(fd, buf, count, offset);
+}
+#define RTSAN_MAYBE_INTERCEPT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
+#else
+#define RTSAN_MAYBE_INTERCEPT_PWRITE64
+#endif // SANITIZER_INTERCEPT_PWRITE64
+
INTERCEPTOR(ssize_t, writev, int fd, const struct iovec *iov, int iovcnt) {
__rtsan_expect_not_realtime("writev");
return REAL(writev)(fd, iov, iovcnt);
@@ -420,20 +528,27 @@ void __rtsan::InitializeInterceptors() {
#endif
INTERCEPT_FUNCTION(open);
+ RTSAN_MAYBE_INTERCEPT_OPEN64;
INTERCEPT_FUNCTION(openat);
+ RTSAN_MAYBE_INTERCEPT_OPENAT64;
INTERCEPT_FUNCTION(close);
INTERCEPT_FUNCTION(fopen);
+ RTSAN_MAYBE_INTERCEPT_FOPEN64;
INTERCEPT_FUNCTION(fread);
INTERCEPT_FUNCTION(read);
INTERCEPT_FUNCTION(write);
INTERCEPT_FUNCTION(pread);
+ RTSAN_MAYBE_INTERCEPT_PREAD64;
INTERCEPT_FUNCTION(readv);
INTERCEPT_FUNCTION(pwrite);
+ RTSAN_MAYBE_INTERCEPT_PWRITE64;
INTERCEPT_FUNCTION(writev);
INTERCEPT_FUNCTION(fwrite);
INTERCEPT_FUNCTION(fclose);
INTERCEPT_FUNCTION(fcntl);
+ RTSAN_MAYBE_INTERCEPT_FCNTL64;
INTERCEPT_FUNCTION(creat);
+ RTSAN_MAYBE_INTERCEPT_CREAT64;
INTERCEPT_FUNCTION(puts);
INTERCEPT_FUNCTION(fputs);
diff --git a/compiler-rt/lib/rtsan/tests/CMakeLists.txt b/compiler-rt/lib/rtsan/tests/CMakeLists.txt
index 5883d33d31895f..0529917bc895ce 100644
--- a/compiler-rt/lib/rtsan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/rtsan/tests/CMakeLists.txt
@@ -76,6 +76,18 @@ foreach(arch ${RTSAN_TEST_ARCH})
CFLAGS ${RTSAN_UNITTEST_CFLAGS} -fsanitize=realtime
LINK_FLAGS ${RTSAN_UNITTEST_LINK_FLAGS} -fsanitize=realtime)
+ check_symbol_exists(__GLIBC__ stdio.h RTSAN_USING_GLIBC)
+ if (RTSAN_USING_GLIBC)
+ set(RtsanTestObjects_FileOffset64)
+ generate_compiler_rt_tests(RtsanTestObjects_FileOffset64
+ RtsanUnitTests "Rtsan-${arch}-FileOffset64-Test" ${arch}
+ COMPILE_DEPS ${RTSAN_UNITTEST_HEADERS}
+ SOURCES ${RTSAN_INST_TEST_SOURCES} ${COMPILER_RT_GOOGLETEST_SOURCES}
+ DEPS rtsan
+ CFLAGS ${RTSAN_UNITTEST_CFLAGS} -D_FILE_OFFSET_BITS=64 -fsanitize=realtime
+ LINK_FLAGS ${RTSAN_UNITTEST_LINK_FLAGS} -fsanitize=realtime)
+ endif()
+
set(RTSAN_TEST_RUNTIME RTRtsanTest.${arch})
if(APPLE)
set(RTSAN_TEST_RUNTIME_OBJECTS
diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp
index 0eeaf9da67098e..2a9c73c3c778e8 100644
--- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp
+++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors.cpp
@@ -37,6 +37,24 @@
#include <sys/socket.h>
#include <sys/uio.h>
+#if _FILE_OFFSET_BITS == 64 && SANITIZER_GLIBC
+const char *const kCreatFunctionName = "creat64";
+const char *const kFcntlFunctionName = "fcntl64";
+const char *const kFopenFunctionName = "fopen64";
+const char *const kOpenAtFunctionName = "openat64";
+const char *const kOpenFunctionName = "open64";
+const char *const kPreadFunctionName = "pread64";
+const char *const kPwriteFunctionName = "pwrite64";
+#else
+const char *const kCreatFunctionName = "creat";
+const char *const kFcntlFunctionName = "fcntl";
+const char *const kFopenFunctionName = "fopen";
+const char *const kOpenAtFunctionName = "openat";
+const char *const kOpenFunctionName = "open";
+const char *const kPreadFunctionName = "pread";
+const char *const kPwriteFunctionName = "pwrite";
+#endif
+
using namespace testing;
using namespace rtsan_testing;
using namespace std::chrono_literals;
@@ -183,13 +201,13 @@ TEST(TestRtsanInterceptors, NanosleepDiesWhenRealtime) {
TEST_F(RtsanFileTest, OpenDiesWhenRealtime) {
auto func = [this]() { open(GetTemporaryFilePath(), O_RDONLY); };
- ExpectRealtimeDeath(func, "open");
+ ExpectRealtimeDeath(func, kOpenFunctionName);
ExpectNonRealtimeSurvival(func);
}
TEST_F(RtsanFileTest, OpenatDiesWhenRealtime) {
auto func = [this]() { openat(0, GetTemporaryFilePath(), O_RDONLY); };
- ExpectRealtimeDeath(func, "openat");
+ ExpectRealtimeDeath(func, kOpenAtFunctionName);
ExpectNonRealtimeSurvival(func);
}
@@ -214,13 +232,13 @@ TEST_F(RtsanFileTest, OpenCreatesFileWithProperMode) {
TEST_F(RtsanFileTest, CreatDiesWhenRealtime) {
auto func = [this]() { creat(GetTemporaryFilePath(), S_IWOTH | S_IROTH); };
- ExpectRealtimeDeath(func, "creat");
+ ExpectRealtimeDeath(func, kCreatFunctionName);
ExpectNonRealtimeSurvival(func);
}
TEST(TestRtsanInterceptors, FcntlDiesWhenRealtime) {
auto func = []() { fcntl(0, F_GETFL); };
- ExpectRealtimeDeath(func, "fcntl");
+ ExpectRealtimeDeath(func, kFcntlFunctionName);
ExpectNonRealtimeSurvival(func);
}
@@ -239,7 +257,7 @@ TEST_F(RtsanFileTest, FcntlFlockDiesWhenRealtime) {
ASSERT_THAT(fcntl(fd, F_GETLK, &lock), Eq(0));
ASSERT_THAT(lock.l_type, F_UNLCK);
};
- ExpectRealtimeDeath(func, "fcntl");
+ ExpectRealtimeDeath(func, kFcntlFunctionName);
ExpectNonRealtimeSurvival(func);
close(fd);
@@ -261,7 +279,7 @@ TEST_F(RtsanFileTest, FcntlSetFdDiesWhenRealtime) {
ASSERT_THAT(fcntl(fd, F_GETFD), Eq(old_flags));
};
- ExpectRealtimeDeath(func, "fcntl");
+ ExpectRealtimeDeath(func, kFcntlFunctionName);
ExpectNonRealtimeSurvival(func);
close(fd);
@@ -278,7 +296,8 @@ TEST_F(RtsanFileTest, FopenDiesWhenRealtime) {
auto fd = fopen(GetTemporaryFilePath(), "w");
EXPECT_THAT(fd, Ne(nullptr));
};
- ExpectRealtimeDeath(func, "fopen");
+
+ ExpectRealtimeDeath(func, kFopenFunctionName);
ExpectNonRealtimeSurvival(func);
}
@@ -366,7 +385,7 @@ TEST_F(RtsanOpenedFileTest, PreadDiesWhenRealtime) {
char c{};
pread(GetOpenFd(), &c, 1, 0);
};
- ExpectRealtimeDeath(Func, "pread");
+ ExpectRealtimeDeath(Func, kPreadFunctionName);
ExpectNonRealtimeSurvival(Func);
}
@@ -385,7 +404,7 @@ TEST_F(RtsanOpenedFileTest, PwriteDiesWhenRealtime) {
char c = 'a';
pwrite(GetOpenFd(), &c, 1, 0);
};
- ExpectRealtimeDeath(Func, "pwrite");
+ ExpectRealtimeDeath(Func, kPwriteFunctionName);
ExpectNonRealtimeSurvival(Func);
}
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 7d7ed9bc07ccfe..e71a6bcd6a8371 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -183,6 +183,11 @@
#define SANITIZER_INTERCEPT_FPUTS SI_POSIX
#define SANITIZER_INTERCEPT_PUTS SI_POSIX
+#define SANITIZER_INTERCEPT_CREAT64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_FCNTL64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_OPEN64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_OPENAT64 (SI_GLIBC || SI_SOLARIS32)
+
#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
|
CC for review @davidtrevelyan @yingcong-wu would you ensure this fixes the tests on your system? |
generate_compiler_rt_tests(RtsanTestObjects_FileOffset64 | ||
RtsanUnitTests "Rtsan-${arch}-FileOffset64-Test" ${arch} | ||
COMPILE_DEPS ${RTSAN_UNITTEST_HEADERS} | ||
SOURCES ${RTSAN_INST_TEST_SOURCES} ${COMPILER_RT_GOOGLETEST_SOURCES} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to compile all the test source files again here in a new target? I don't yet understand why it's not OK just to define -D_FILE_OFFSET_BITS=64
here on the single test target instead...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought is that we need to test both configurations if they are available.
If we add a new interceptor for foo
that also has a foo64
that we don't know about, running both configurations should notify us of that missing interceptor. If we just pass in -D_FILE_OFFSET_BITS=64, we are only testing foo64
This patch works for me. 👍 |
0e23e79
to
5db7f56
Compare
From #107988
We were not intercepting the 64 bit versions of these calls, leading to tests failing when _FILE_OFFSET_BITS = 64.
Add the appropriate interceptors, and add tests for them