| 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 | |