diff --git a/compiler-rt/lib/msan/tests/msan_test.cpp b/compiler-rt/lib/msan/tests/msan_test.cpp --- a/compiler-rt/lib/msan/tests/msan_test.cpp +++ b/compiler-rt/lib/msan/tests/msan_test.cpp @@ -4679,6 +4679,58 @@ munmap(q, 4096); } +TEST(MemorySanitizer, timer_create) { + struct sigevent sev {}; + sev.sigev_notify = SIGEV_NONE; + timer_t timerid; + EXPECT_POISONED(timerid); + ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid)); + EXPECT_NOT_POISONED(timerid); +} + +TEST(MemorySanitizer, timer_create_umr) { + struct sigevent sev; + timer_t timerid; + EXPECT_POISONED(sev); + EXPECT_UMR(timer_create(CLOCK_REALTIME, &sev, &timerid)); +} + +TEST(MemorySanitizer, timer_settime) { + struct sigevent sev {}; + sev.sigev_notify = SIGEV_NONE; + timer_t timerid; + ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid)); + struct itimerspec new_value {}; + new_value.it_interval.tv_sec = 10; + new_value.it_value.tv_sec = 10; + struct itimerspec old_value; + EXPECT_POISONED(old_value); + ASSERT_EQ(0, timer_settime(timerid, 0, &new_value, &old_value)); + EXPECT_NOT_POISONED(old_value); +} + +TEST(MemorySanitizer, timer_settime_umr) { + struct sigevent sev {}; + sev.sigev_notify = SIGEV_NONE; + timer_t timerid; + ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid)); + struct itimerspec new_value; + struct itimerspec old_value; + EXPECT_POISONED(new_value); + EXPECT_UMR(timer_settime(timerid, 0, &new_value, &old_value)); +} + +TEST(MemorySanitizer, timer_gettime) { + struct sigevent sev {}; + sev.sigev_notify = SIGEV_NONE; + timer_t timerid; + ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid)); + struct itimerspec curr_value; + EXPECT_POISONED(curr_value); + ASSERT_EQ(0, timer_gettime(timerid, &curr_value)); + EXPECT_NOT_POISONED(curr_value); +} + #if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE TEST(MemorySanitizer, MallocUsableSizeTest) { const size_t kArraySize = 100; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -10211,6 +10211,62 @@ #define INIT___XUNAME #endif +#if SANITIZER_INTERCEPT_TIMER_CREATE +INTERCEPTOR(int, timer_create, __sanitizer_clockid_t clockid, + struct sigevent *sevp, __sanitizer_timer_t *timerid) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timer_create, clockid, sevp, timerid); + COMMON_INTERCEPTOR_READ_RANGE(ctx, sevp, struct_sigevent_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(timer_create)(clockid, sevp, timerid); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, timerid, sizeof(*timerid)); + return res; +} +#define INIT_TIMER_CREATE COMMON_INTERCEPT_FUNCTION(timer_create) +#else +#define INIT_TIMER_CREATE +#endif + +#if SANITIZER_INTERCEPT_TIMER_SETTIME +INTERCEPTOR(int, timer_settime, __sanitizer_timer_t timerid, int flags, + const void *new_value, void *old_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timer_settime, timerid, flags, new_value, + old_value); + COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(timer_settime)(timerid, flags, new_value, old_value); + if (!res && old_value) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz); + return res; +} +#define INIT_TIMER_SETTIME COMMON_INTERCEPT_FUNCTION(timer_settime) +#else +#define INIT_TIMER_SETTIME +#endif + +#if SANITIZER_INTERCEPT_TIMER_GETTIME +INTERCEPTOR(int, timer_gettime, __sanitizer_timer_t timerid, void *curr_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timer_gettime, timerid, curr_value); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(timer_gettime)(timerid, curr_value); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz); + return res; +} +#define INIT_TIMER_GETTIME COMMON_INTERCEPT_FUNCTION(timer_gettime) +#else +#define INIT_TIMER_GETTIME +#endif + #include "sanitizer_common_interceptors_netbsd_compat.inc" static void InitializeCommonInterceptors() { @@ -10529,6 +10585,9 @@ INIT_SIGALTSTACK; INIT_UNAME; INIT___XUNAME; + INIT_TIMER_CREATE; + INIT_TIMER_SETTIME; + INIT_TIMER_GETTIME; INIT___PRINTF_CHK; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -588,6 +588,9 @@ (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD +#define SANITIZER_INTERCEPT_TIMER_CREATE SI_POSIX +#define SANITIZER_INTERCEPT_TIMER_SETTIME SI_POSIX +#define SANITIZER_INTERCEPT_TIMER_GETTIME SI_POSIX #define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD // This macro gives a way for downstream users to override the above diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -511,6 +511,7 @@ #if SANITIZER_LINUX typedef int __sanitizer_clockid_t; +typedef void *__sanitizer_timer_t; #endif #if SANITIZER_LINUX diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/timer.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/timer.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/timer.cpp @@ -0,0 +1,40 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t | FileCheck %s +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + struct sigevent sev {}; + sev.sigev_notify = SIGEV_NONE; + timer_t timerid; + assert(timer_create(CLOCK_REALTIME, &sev, &timerid) == 0); + + struct itimerspec new_value {}; + new_value.it_value.tv_sec = 10; + new_value.it_value.tv_nsec = 1000000; + new_value.it_interval.tv_sec = new_value.it_value.tv_sec; + new_value.it_interval.tv_nsec = new_value.it_value.tv_nsec; + + assert(timer_settime(timerid, 0, &new_value, nullptr) == 0); + + struct itimerspec old_value; + assert(timer_settime(timerid, 0, &new_value, &old_value) == 0); + assert(old_value.it_interval.tv_sec == new_value.it_interval.tv_sec); + assert(old_value.it_interval.tv_nsec == new_value.it_interval.tv_nsec); + assert(old_value.it_value.tv_sec <= new_value.it_value.tv_sec); + assert(old_value.it_value.tv_nsec <= new_value.it_value.tv_nsec); + + struct itimerspec curr_value; + assert(timer_gettime(timerid, &curr_value) == 0); + assert(curr_value.it_interval.tv_sec == new_value.it_interval.tv_sec); + assert(curr_value.it_interval.tv_nsec == new_value.it_interval.tv_nsec); + assert(curr_value.it_value.tv_sec <= new_value.it_value.tv_sec); + assert(curr_value.it_value.tv_nsec <= new_value.it_value.tv_nsec); + + printf("DONE\n"); + // CHECK: DONE + + return 0; +}