Skip to content

Commit c2aab0d

Browse files
committed
[MSAN] add interceptor for timer_create, timer_settime, timer_gettime
Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D120602
1 parent 4bfd8a2 commit c2aab0d

File tree

8 files changed

+124
-0
lines changed

8 files changed

+124
-0
lines changed

compiler-rt/lib/msan/tests/msan_test.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4679,6 +4679,40 @@ TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) {
46794679
munmap(q, 4096);
46804680
}
46814681

4682+
TEST(MemorySanitizer, timer_create) {
4683+
struct sigevent sev {};
4684+
sev.sigev_notify = SIGEV_NONE;
4685+
timer_t timerid;
4686+
EXPECT_POISONED(timerid);
4687+
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid));
4688+
EXPECT_NOT_POISONED(timerid);
4689+
}
4690+
4691+
TEST(MemorySanitizer, timer_settime) {
4692+
struct sigevent sev {};
4693+
sev.sigev_notify = SIGEV_NONE;
4694+
timer_t timerid;
4695+
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid));
4696+
struct itimerspec new_value {};
4697+
new_value.it_interval.tv_sec = 10;
4698+
new_value.it_value.tv_sec = 10;
4699+
struct itimerspec old_value;
4700+
EXPECT_POISONED(old_value);
4701+
ASSERT_EQ(0, timer_settime(timerid, 0, &new_value, &old_value));
4702+
EXPECT_NOT_POISONED(old_value);
4703+
}
4704+
4705+
TEST(MemorySanitizer, timer_gettime) {
4706+
struct sigevent sev {};
4707+
sev.sigev_notify = SIGEV_NONE;
4708+
timer_t timerid;
4709+
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &sev, &timerid));
4710+
struct itimerspec curr_value;
4711+
EXPECT_POISONED(curr_value);
4712+
ASSERT_EQ(0, timer_gettime(timerid, &curr_value));
4713+
EXPECT_NOT_POISONED(curr_value);
4714+
}
4715+
46824716
#if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE
46834717
TEST(MemorySanitizer, MallocUsableSizeTest) {
46844718
const size_t kArraySize = 100;

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10211,6 +10211,51 @@ INTERCEPTOR(int, __xuname, int size, void *utsname) {
1021110211
#define INIT___XUNAME
1021210212
#endif
1021310213

10214+
#if SANITIZER_INTERCEPT_TIMER
10215+
INTERCEPTOR(int, timer_create, __sanitizer_clockid_t clockid,
10216+
struct sigevent *sevp, __sanitizer_timer_t *timerid) {
10217+
void *ctx;
10218+
COMMON_INTERCEPTOR_ENTER(ctx, timer_create, clockid, sevp, timerid);
10219+
// FIXME: under ASan the call below may write to freed memory and corrupt
10220+
// its metadata. See
10221+
// https://github.com/google/sanitizers/issues/321.
10222+
int res = REAL(timer_create)(clockid, sevp, timerid);
10223+
if (!res)
10224+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, timerid, sizeof(*timerid));
10225+
return res;
10226+
}
10227+
INTERCEPTOR(int, timer_settime, __sanitizer_timer_t timerid, int flags,
10228+
const void *new_value, void *old_value) {
10229+
void *ctx;
10230+
COMMON_INTERCEPTOR_ENTER(ctx, timer_settime, timerid, flags, new_value,
10231+
old_value);
10232+
// FIXME: under ASan the call below may write to freed memory and corrupt
10233+
// its metadata. See
10234+
// https://github.com/google/sanitizers/issues/321.
10235+
int res = REAL(timer_settime)(timerid, flags, new_value, old_value);
10236+
if (!res && old_value)
10237+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
10238+
return res;
10239+
}
10240+
INTERCEPTOR(int, timer_gettime, __sanitizer_timer_t timerid, void *curr_value) {
10241+
void *ctx;
10242+
COMMON_INTERCEPTOR_ENTER(ctx, timer_gettime, timerid, curr_value);
10243+
// FIXME: under ASan the call below may write to freed memory and corrupt
10244+
// its metadata. See
10245+
// https://github.com/google/sanitizers/issues/321.
10246+
int res = REAL(timer_gettime)(timerid, curr_value);
10247+
if (!res)
10248+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
10249+
return res;
10250+
}
10251+
#define INIT_TIMER \
10252+
COMMON_INTERCEPT_FUNCTION(timer_create); \
10253+
COMMON_INTERCEPT_FUNCTION(timer_settime); \
10254+
COMMON_INTERCEPT_FUNCTION(timer_gettime);
10255+
#else
10256+
#define INIT_TIMER
10257+
#endif
10258+
1021410259
#include "sanitizer_common_interceptors_netbsd_compat.inc"
1021510260

1021610261
static void InitializeCommonInterceptors() {
@@ -10529,6 +10574,7 @@ static void InitializeCommonInterceptors() {
1052910574
INIT_SIGALTSTACK;
1053010575
INIT_UNAME;
1053110576
INIT___XUNAME;
10577+
INIT_TIMER;
1053210578

1053310579
INIT___PRINTF_CHK;
1053410580
}

compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@
588588
(SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386))
589589
#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
590590
#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
591+
#define SANITIZER_INTERCEPT_TIMER \
592+
(SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS)
591593
#define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD
592594

593595
// This macro gives a way for downstream users to override the above

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ struct __sanitizer_dirent {
255255
// 'clock_t' is 32 bits wide on x64 FreeBSD
256256
typedef int __sanitizer_clock_t;
257257
typedef int __sanitizer_clockid_t;
258+
typedef void *__sanitizer_timer_t;
258259

259260
# if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) || \
260261
defined(__mips__)

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ struct __sanitizer_dirent {
259259

260260
typedef int __sanitizer_clock_t;
261261
typedef int __sanitizer_clockid_t;
262+
typedef void *__sanitizer_timer_t;
262263

263264
typedef u32 __sanitizer___kernel_uid_t;
264265
typedef u32 __sanitizer___kernel_gid_t;

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ typedef long __sanitizer_clock_t;
511511

512512
#if SANITIZER_LINUX
513513
typedef int __sanitizer_clockid_t;
514+
typedef void *__sanitizer_timer_t;
514515
#endif
515516

516517
#if SANITIZER_LINUX

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_solaris.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ struct __sanitizer_dirent64 {
235235

236236
typedef long __sanitizer_clock_t;
237237
typedef int __sanitizer_clockid_t;
238+
typedef void *__sanitizer_timer_t;
238239

239240
// This thing depends on the platform. We are only interested in the upper
240241
// limit. Verified with a compiler assert in .cpp.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %clangxx -O0 -g %s -o %t && %run %t
2+
// UNSUPPORTED: darwin
3+
#include <assert.h>
4+
#include <signal.h>
5+
#include <stdio.h>
6+
#include <string.h>
7+
#include <time.h>
8+
9+
int main(int argc, char **argv) {
10+
struct sigevent sev {};
11+
sev.sigev_notify = SIGEV_NONE;
12+
timer_t timerid;
13+
assert(timer_create(CLOCK_REALTIME, &sev, &timerid) == 0);
14+
15+
struct itimerspec new_value {};
16+
new_value.it_value.tv_sec = 10;
17+
new_value.it_value.tv_nsec = 1000000;
18+
new_value.it_interval.tv_sec = new_value.it_value.tv_sec;
19+
new_value.it_interval.tv_nsec = new_value.it_value.tv_nsec;
20+
21+
assert(timer_settime(timerid, 0, &new_value, nullptr) == 0);
22+
23+
struct itimerspec old_value;
24+
assert(timer_settime(timerid, 0, &new_value, &old_value) == 0);
25+
assert(old_value.it_interval.tv_sec == new_value.it_interval.tv_sec);
26+
assert(old_value.it_interval.tv_nsec == new_value.it_interval.tv_nsec);
27+
assert(old_value.it_value.tv_sec <= new_value.it_value.tv_sec);
28+
assert(old_value.it_value.tv_nsec <= new_value.it_value.tv_nsec);
29+
30+
struct itimerspec curr_value;
31+
assert(timer_gettime(timerid, &curr_value) == 0);
32+
assert(curr_value.it_interval.tv_sec == new_value.it_interval.tv_sec);
33+
assert(curr_value.it_interval.tv_nsec == new_value.it_interval.tv_nsec);
34+
assert(curr_value.it_value.tv_sec <= new_value.it_value.tv_sec);
35+
assert(curr_value.it_value.tv_nsec <= new_value.it_value.tv_nsec);
36+
37+
return 0;
38+
}

0 commit comments

Comments
 (0)