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,40 @@ 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_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_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,51 @@ #define INIT___XUNAME #endif +#if SANITIZER_INTERCEPT_TIMER +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); + // 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; +} +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); + // 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; +} +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 \ + COMMON_INTERCEPT_FUNCTION(timer_create); \ + COMMON_INTERCEPT_FUNCTION(timer_settime); \ + COMMON_INTERCEPT_FUNCTION(timer_gettime); +#else +#define INIT_TIMER +#endif + #include "sanitizer_common_interceptors_netbsd_compat.inc" static void InitializeCommonInterceptors() { @@ -10529,6 +10574,7 @@ INIT_SIGALTSTACK; INIT_UNAME; INIT___XUNAME; + INIT_TIMER; 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,8 @@ (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD +#define SANITIZER_INTERCEPT_TIMER \ + (SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS) #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_freebsd.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h @@ -255,6 +255,7 @@ // 'clock_t' is 32 bits wide on x64 FreeBSD typedef int __sanitizer_clock_t; typedef int __sanitizer_clockid_t; +typedef void *__sanitizer_timer_t; # if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \ defined(__mips__) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -259,6 +259,7 @@ typedef int __sanitizer_clock_t; typedef int __sanitizer_clockid_t; +typedef void *__sanitizer_timer_t; typedef u32 __sanitizer___kernel_uid_t; typedef u32 __sanitizer___kernel_gid_t; 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/lib/sanitizer_common/sanitizer_platform_limits_solaris.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -235,6 +235,7 @@ typedef long __sanitizer_clock_t; typedef int __sanitizer_clockid_t; +typedef void *__sanitizer_timer_t; // This thing depends on the platform. We are only interested in the upper // limit. Verified with a compiler assert in .cpp. diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/timer.cpp b/compiler-rt/test/sanitizer_common/TestCases/Posix/timer.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/timer.cpp @@ -0,0 +1,38 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t +// UNSUPPORTED: darwin +#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; + + 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); + + assert(timer_delete(timerid) == 0); + + return 0; +}