1 | //===-- tsan_posix.cpp ----------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of ThreadSanitizer (TSan), a race detector. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | #include "tsan_interface.h" |
13 | #include "tsan_posix_util.h" |
14 | #include "tsan_test_util.h" |
15 | #include "gtest/gtest.h" |
16 | #include <pthread.h> |
17 | |
18 | struct thread_key { |
19 | pthread_key_t key; |
20 | pthread_mutex_t *mtx; |
21 | int val; |
22 | int *cnt; |
23 | thread_key(pthread_key_t key, pthread_mutex_t *mtx, int val, int *cnt) |
24 | : key(key) |
25 | , mtx(mtx) |
26 | , val(val) |
27 | , cnt(cnt) { |
28 | } |
29 | }; |
30 | |
31 | static void thread_secific_dtor(void *v) { |
32 | thread_key *k = (thread_key *)v; |
33 | EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: k->mtx), 0); |
34 | (*k->cnt)++; |
35 | __tsan_write4(addr: &k->cnt); |
36 | EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: k->mtx), 0); |
37 | if (k->val == 42) { |
38 | // Okay. |
39 | } else if (k->val == 43 || k->val == 44) { |
40 | k->val--; |
41 | EXPECT_EQ(pthread_setspecific(key: k->key, pointer: k), 0); |
42 | } else { |
43 | ASSERT_TRUE(false); |
44 | } |
45 | } |
46 | |
47 | static void *dtors_thread(void *p) { |
48 | thread_key *k = (thread_key *)p; |
49 | EXPECT_EQ(pthread_setspecific(key: k->key, pointer: k), 0); |
50 | return 0; |
51 | } |
52 | |
53 | TEST(Posix, ThreadSpecificDtors) { |
54 | int cnt = 0; |
55 | pthread_key_t key; |
56 | EXPECT_EQ(pthread_key_create(&key, thread_secific_dtor), 0); |
57 | pthread_mutex_t mtx; |
58 | EXPECT_EQ(__interceptor_pthread_mutex_init(&mtx, 0), 0); |
59 | pthread_t th[3]; |
60 | thread_key k1 = thread_key(key, &mtx, 42, &cnt); |
61 | thread_key k2 = thread_key(key, &mtx, 43, &cnt); |
62 | thread_key k3 = thread_key(key, &mtx, 44, &cnt); |
63 | EXPECT_EQ(__interceptor_pthread_create(&th[0], 0, dtors_thread, &k1), 0); |
64 | EXPECT_EQ(__interceptor_pthread_create(&th[1], 0, dtors_thread, &k2), 0); |
65 | EXPECT_EQ(__interceptor_pthread_join(th[0], 0), 0); |
66 | EXPECT_EQ(__interceptor_pthread_create(&th[2], 0, dtors_thread, &k3), 0); |
67 | EXPECT_EQ(__interceptor_pthread_join(th[1], 0), 0); |
68 | EXPECT_EQ(__interceptor_pthread_join(th[2], 0), 0); |
69 | EXPECT_EQ(pthread_key_delete(key), 0); |
70 | EXPECT_EQ(6, cnt); |
71 | } |
72 | |
73 | #if !defined(__aarch64__) && !defined(__APPLE__) |
74 | static __thread int local_var; |
75 | |
76 | static void *local_thread(void *p) { |
77 | __tsan_write1(addr: &local_var); |
78 | __tsan_write1(addr: &p); |
79 | if (p == 0) |
80 | return 0; |
81 | const int kThreads = 4; |
82 | pthread_t th[kThreads]; |
83 | for (int i = 0; i < kThreads; i++) |
84 | EXPECT_EQ(__interceptor_pthread_create(thread: &th[i], attr: 0, start_routine: local_thread, |
85 | arg: (void *)((long)p - 1)), |
86 | 0); |
87 | for (int i = 0; i < kThreads; i++) |
88 | EXPECT_EQ(__interceptor_pthread_join(thread: th[i], value_ptr: 0), 0); |
89 | return 0; |
90 | } |
91 | #endif |
92 | |
93 | TEST(Posix, ThreadLocalAccesses) { |
94 | // The test is failing with high thread count for aarch64. |
95 | // FIXME: track down the issue and re-enable the test. |
96 | // On Darwin, we're running unit tests without interceptors and __thread is |
97 | // using malloc and free, which causes false data race reports. On rare |
98 | // occasions on powerpc64le this test also fails. |
99 | #if !defined(__aarch64__) && !defined(__APPLE__) && !defined(powerpc64le) |
100 | local_thread(p: (void*)2); |
101 | #endif |
102 | } |
103 | |
104 | struct CondContext { |
105 | pthread_mutex_t m; |
106 | pthread_cond_t c; |
107 | int data; |
108 | }; |
109 | |
110 | static void *cond_thread(void *p) { |
111 | CondContext &ctx = *static_cast<CondContext*>(p); |
112 | |
113 | EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0); |
114 | EXPECT_EQ(ctx.data, 0); |
115 | ctx.data = 1; |
116 | EXPECT_EQ(__interceptor_pthread_cond_signal(cond: &ctx.c), 0); |
117 | EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0); |
118 | |
119 | EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0); |
120 | while (ctx.data != 2) |
121 | EXPECT_EQ(__interceptor_pthread_cond_wait(cond: &ctx.c, mutex: &ctx.m), 0); |
122 | EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0); |
123 | |
124 | EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0); |
125 | ctx.data = 3; |
126 | EXPECT_EQ(pthread_cond_broadcast(cond: &ctx.c), 0); |
127 | EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0); |
128 | |
129 | return 0; |
130 | } |
131 | |
132 | TEST(Posix, CondBasic) { |
133 | CondContext ctx; |
134 | EXPECT_EQ(__interceptor_pthread_mutex_init(mutex: &ctx.m, attr: 0), 0); |
135 | EXPECT_EQ(__interceptor_pthread_cond_init(cond: &ctx.c, attr: 0), 0); |
136 | ctx.data = 0; |
137 | pthread_t th; |
138 | EXPECT_EQ(__interceptor_pthread_create(thread: &th, attr: 0, start_routine: cond_thread, arg: &ctx), 0); |
139 | |
140 | EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0); |
141 | while (ctx.data != 1) |
142 | EXPECT_EQ(__interceptor_pthread_cond_wait(cond: &ctx.c, mutex: &ctx.m), 0); |
143 | ctx.data = 2; |
144 | EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0); |
145 | EXPECT_EQ(pthread_cond_broadcast(cond: &ctx.c), 0); |
146 | |
147 | EXPECT_EQ(__interceptor_pthread_mutex_lock(mutex: &ctx.m), 0); |
148 | while (ctx.data != 3) |
149 | EXPECT_EQ(__interceptor_pthread_cond_wait(cond: &ctx.c, mutex: &ctx.m), 0); |
150 | EXPECT_EQ(__interceptor_pthread_mutex_unlock(mutex: &ctx.m), 0); |
151 | |
152 | EXPECT_EQ(__interceptor_pthread_join(thread: th, value_ptr: 0), 0); |
153 | EXPECT_EQ(__interceptor_pthread_cond_destroy(cond: &ctx.c), 0); |
154 | EXPECT_EQ(__interceptor_pthread_mutex_destroy(mutex: &ctx.m), 0); |
155 | } |
156 | |