1//===-- tsan_test_util_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// Test utils, Linux, FreeBSD, NetBSD and Darwin implementation.
12//===----------------------------------------------------------------------===//
13
14#include "sanitizer_common/sanitizer_atomic.h"
15#include "tsan_interface.h"
16#include "tsan_posix_util.h"
17#include "tsan_rtl.h"
18#include "tsan_test_util.h"
19#include "tsan_report.h"
20
21#include <assert.h>
22#include <pthread.h>
23#include <stdio.h>
24#include <stdint.h>
25#include <string.h>
26#include <unistd.h>
27#include <errno.h>
28
29#define CALLERPC (__builtin_return_address(0))
30
31static __thread bool expect_report;
32static __thread bool expect_report_reported;
33static __thread __tsan::ReportType expect_report_type;
34
35void ThreadSanitizer::TearDown() {
36  __tsan::ctx->racy_stacks.Reset();
37}
38
39static void *BeforeInitThread(void *param) {
40  (void)param;
41  return 0;
42}
43
44static void AtExit() {
45}
46
47void TestMutexBeforeInit() {
48  // Mutexes must be usable before __tsan_init();
49  pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
50  __interceptor_pthread_mutex_lock(&mtx);
51  __interceptor_pthread_mutex_unlock(&mtx);
52  __interceptor_pthread_mutex_destroy(&mtx);
53  pthread_t thr;
54  __interceptor_pthread_create(&thr, 0, BeforeInitThread, 0);
55  __interceptor_pthread_join(thr, 0);
56  atexit(AtExit);
57}
58
59namespace __tsan {
60bool OnReport(const ReportDesc *rep, bool suppressed) {
61  if (expect_report) {
62    if (rep->typ != expect_report_type) {
63      printf("Expected report of type %d, got type %d\n",
64             (int)expect_report_type, (int)rep->typ);
65      EXPECT_TRUE(false) << "Wrong report type";
66      return false;
67    }
68  } else {
69    EXPECT_TRUE(false) << "Unexpected report";
70    return false;
71  }
72  expect_report_reported = true;
73  return true;
74}
75}  // namespace __tsan
76
77static void* allocate_addr(int size, int offset_from_aligned = 0) {
78  static uintptr_t foo;
79  static __tsan::atomic_uintptr_t uniq = {(uintptr_t)&foo}; // Some real address.
80  const int kAlign = 16;
81  CHECK(offset_from_aligned < kAlign);
82  size = (size + 2 * kAlign) & ~(kAlign - 1);
83  uintptr_t addr = atomic_fetch_add(&uniq, size, __tsan::memory_order_relaxed);
84  return (void*)(addr + offset_from_aligned);
85}
86
87MemLoc::MemLoc(int offset_from_aligned)
88  : loc_(allocate_addr(16, offset_from_aligned)) {
89}
90
91MemLoc::~MemLoc() {
92}
93
94UserMutex::UserMutex(Type type) : alive_(), type_(type) {}
95
96UserMutex::~UserMutex() { CHECK(!alive_); }
97
98void UserMutex::Init() {
99  CHECK(!alive_);
100  alive_ = true;
101  if (type_ == Normal)
102    CHECK_EQ(__interceptor_pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
103#ifndef __APPLE__
104  else if (type_ == Spin)
105    CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
106#endif
107  else if (type_ == RW)
108    CHECK_EQ(__interceptor_pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
109  else
110    CHECK(0);
111}
112
113void UserMutex::StaticInit() {
114  CHECK(!alive_);
115  CHECK(type_ == Normal);
116  alive_ = true;
117  pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
118  memcpy(mtx_, &tmp, sizeof(tmp));
119}
120
121void UserMutex::Destroy() {
122  CHECK(alive_);
123  alive_ = false;
124  if (type_ == Normal)
125    CHECK_EQ(__interceptor_pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
126#ifndef __APPLE__
127  else if (type_ == Spin)
128    CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
129#endif
130  else if (type_ == RW)
131    CHECK_EQ(__interceptor_pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
132}
133
134void UserMutex::Lock() {
135  CHECK(alive_);
136  if (type_ == Normal)
137    CHECK_EQ(__interceptor_pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
138#ifndef __APPLE__
139  else if (type_ == Spin)
140    CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
141#endif
142  else if (type_ == RW)
143    CHECK_EQ(__interceptor_pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
144}
145
146bool UserMutex::TryLock() {
147  CHECK(alive_);
148  if (type_ == Normal)
149    return __interceptor_pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
150#ifndef __APPLE__
151  else if (type_ == Spin)
152    return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
153#endif
154  else if (type_ == RW)
155    return __interceptor_pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
156  return false;
157}
158
159void UserMutex::Unlock() {
160  CHECK(alive_);
161  if (type_ == Normal)
162    CHECK_EQ(__interceptor_pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
163#ifndef __APPLE__
164  else if (type_ == Spin)
165    CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
166#endif
167  else if (type_ == RW)
168    CHECK_EQ(__interceptor_pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
169}
170
171void UserMutex::ReadLock() {
172  CHECK(alive_);
173  CHECK(type_ == RW);
174  CHECK_EQ(__interceptor_pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0);
175}
176
177bool UserMutex::TryReadLock() {
178  CHECK(alive_);
179  CHECK(type_ == RW);
180  return __interceptor_pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) ==  0;
181}
182
183void UserMutex::ReadUnlock() {
184  CHECK(alive_);
185  CHECK(type_ == RW);
186  CHECK_EQ(__interceptor_pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
187}
188
189struct Event {
190  enum Type {
191    SHUTDOWN,
192    READ,
193    WRITE,
194    VPTR_UPDATE,
195    CALL,
196    RETURN,
197    MUTEX_CREATE,
198    MUTEX_DESTROY,
199    MUTEX_LOCK,
200    MUTEX_TRYLOCK,
201    MUTEX_UNLOCK,
202    MUTEX_READLOCK,
203    MUTEX_TRYREADLOCK,
204    MUTEX_READUNLOCK,
205    MEMCPY,
206    MEMSET
207  };
208  Type type;
209  void *ptr;
210  uptr arg;
211  uptr arg2;
212  bool res;
213  bool expect_report;
214  __tsan::ReportType report_type;
215
216  explicit Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0)
217      : type(type),
218        ptr(const_cast<void *>(ptr)),
219        arg(arg),
220        arg2(arg2),
221        res(),
222        expect_report(),
223        report_type() {}
224
225  void ExpectReport(__tsan::ReportType type) {
226    expect_report = true;
227    report_type = type;
228  }
229};
230
231struct ScopedThread::Impl {
232  pthread_t thread;
233  bool main;
234  bool detached;
235  __tsan::atomic_uintptr_t event;  // Event*
236
237  static void *ScopedThreadCallback(void *arg);
238  void send(Event *ev);
239  void HandleEvent(Event *ev);
240};
241
242void ScopedThread::Impl::HandleEvent(Event *ev) {
243  CHECK_EQ(expect_report, false);
244  expect_report = ev->expect_report;
245  expect_report_reported = false;
246  expect_report_type = ev->report_type;
247  switch (ev->type) {
248  case Event::READ:
249  case Event::WRITE: {
250    void (*tsan_mop)(void *addr, void *pc) = 0;
251    if (ev->type == Event::READ) {
252      switch (ev->arg /*size*/) {
253        case 1:
254          tsan_mop = __tsan_read1_pc;
255          break;
256        case 2:
257          tsan_mop = __tsan_read2_pc;
258          break;
259        case 4:
260          tsan_mop = __tsan_read4_pc;
261          break;
262        case 8:
263          tsan_mop = __tsan_read8_pc;
264          break;
265        case 16:
266          tsan_mop = __tsan_read16_pc;
267          break;
268      }
269    } else {
270      switch (ev->arg /*size*/) {
271        case 1:
272          tsan_mop = __tsan_write1_pc;
273          break;
274        case 2:
275          tsan_mop = __tsan_write2_pc;
276          break;
277        case 4:
278          tsan_mop = __tsan_write4_pc;
279          break;
280        case 8:
281          tsan_mop = __tsan_write8_pc;
282          break;
283        case 16:
284          tsan_mop = __tsan_write16_pc;
285          break;
286      }
287    }
288    CHECK_NE(tsan_mop, 0);
289#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
290    const int ErrCode = ESOCKTNOSUPPORT;
291#else
292    const int ErrCode = ECHRNG;
293#endif
294    errno = ErrCode;
295    tsan_mop(ev->ptr, (void *)ev->arg2);
296    CHECK_EQ(ErrCode, errno);  // In no case must errno be changed.
297    break;
298  }
299  case Event::VPTR_UPDATE:
300    __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg);
301    break;
302  case Event::CALL:
303    __tsan_func_entry((void*)((uptr)ev->ptr));
304    break;
305  case Event::RETURN:
306    __tsan_func_exit();
307    break;
308  case Event::MUTEX_CREATE:
309    static_cast<UserMutex *>(ev->ptr)->Init();
310    break;
311  case Event::MUTEX_DESTROY:
312    static_cast<UserMutex *>(ev->ptr)->Destroy();
313    break;
314  case Event::MUTEX_LOCK:
315    static_cast<UserMutex *>(ev->ptr)->Lock();
316    break;
317  case Event::MUTEX_TRYLOCK:
318    ev->res = static_cast<UserMutex *>(ev->ptr)->TryLock();
319    break;
320  case Event::MUTEX_UNLOCK:
321    static_cast<UserMutex *>(ev->ptr)->Unlock();
322    break;
323  case Event::MUTEX_READLOCK:
324    static_cast<UserMutex *>(ev->ptr)->ReadLock();
325    break;
326  case Event::MUTEX_TRYREADLOCK:
327    ev->res = static_cast<UserMutex *>(ev->ptr)->TryReadLock();
328    break;
329  case Event::MUTEX_READUNLOCK:
330    static_cast<UserMutex *>(ev->ptr)->ReadUnlock();
331    break;
332  case Event::MEMCPY:
333    __interceptor_memcpy(ev->ptr, (void*)ev->arg, ev->arg2);
334    break;
335  case Event::MEMSET:
336    __interceptor_memset(ev->ptr, ev->arg, ev->arg2);
337    break;
338  default: CHECK(0);
339  }
340  if (expect_report && !expect_report_reported) {
341    printf("Missed expected report of type %d\n", (int)ev->report_type);
342    EXPECT_TRUE(false) << "Missed expected race";
343  }
344  expect_report = false;
345}
346
347void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
348  __tsan_func_entry(CALLERPC);
349  Impl *impl = (Impl*)arg;
350  for (;;) {
351    Event *ev =
352        (Event *)atomic_load(&impl->event, __tsan::memory_order_acquire);
353    if (ev == 0) {
354      sched_yield();
355      continue;
356    }
357    if (ev->type == Event::SHUTDOWN) {
358      atomic_store(&impl->event, 0, __tsan::memory_order_release);
359      break;
360    }
361    impl->HandleEvent(ev);
362    atomic_store(&impl->event, 0, __tsan::memory_order_release);
363  }
364  __tsan_func_exit();
365  return 0;
366}
367
368void ScopedThread::Impl::send(Event *e) {
369  if (main) {
370    HandleEvent(e);
371  } else {
372    CHECK_EQ(atomic_load(&event, __tsan::memory_order_relaxed), 0);
373    atomic_store(&event, (uintptr_t)e, __tsan::memory_order_release);
374    while (atomic_load(&event, __tsan::memory_order_acquire) != 0)
375      sched_yield();
376  }
377}
378
379ScopedThread::ScopedThread(bool detached, bool main) {
380  impl_ = new Impl;
381  impl_->main = main;
382  impl_->detached = detached;
383  atomic_store(&impl_->event, 0, __tsan::memory_order_relaxed);
384  if (!main) {
385    pthread_attr_t attr;
386    pthread_attr_init(&attr);
387    pthread_attr_setdetachstate(
388        &attr, detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
389    pthread_attr_setstacksize(&attr, 64*1024);
390    __interceptor_pthread_create(&impl_->thread, &attr,
391        ScopedThread::Impl::ScopedThreadCallback, impl_);
392  }
393}
394
395ScopedThread::~ScopedThread() {
396  if (!impl_->main) {
397    Event event(Event::SHUTDOWN);
398    impl_->send(&event);
399    if (!impl_->detached)
400      __interceptor_pthread_join(impl_->thread, 0);
401  }
402  delete impl_;
403}
404
405void ScopedThread::Detach() {
406  CHECK(!impl_->main);
407  CHECK(!impl_->detached);
408  impl_->detached = true;
409  __interceptor_pthread_detach(impl_->thread);
410}
411
412void ScopedThread::Access(void *addr, bool is_write,
413                          int size, bool expect_race) {
414  Event event(is_write ? Event::WRITE : Event::READ, addr, size,
415              (uptr)CALLERPC);
416  if (expect_race)
417    event.ExpectReport(__tsan::ReportTypeRace);
418  impl_->send(&event);
419}
420
421void ScopedThread::VptrUpdate(const MemLoc &vptr,
422                              const MemLoc &new_val,
423                              bool expect_race) {
424  Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc());
425  if (expect_race)
426    event.ExpectReport(__tsan::ReportTypeRace);
427  impl_->send(&event);
428}
429
430void ScopedThread::Call(void(*pc)()) {
431  Event event(Event::CALL, (void*)((uintptr_t)pc));
432  impl_->send(&event);
433}
434
435void ScopedThread::Return() {
436  Event event(Event::RETURN);
437  impl_->send(&event);
438}
439
440void ScopedThread::Create(const UserMutex &m) {
441  Event event(Event::MUTEX_CREATE, &m);
442  impl_->send(&event);
443}
444
445void ScopedThread::Destroy(const UserMutex &m) {
446  Event event(Event::MUTEX_DESTROY, &m);
447  impl_->send(&event);
448}
449
450void ScopedThread::Lock(const UserMutex &m) {
451  Event event(Event::MUTEX_LOCK, &m);
452  impl_->send(&event);
453}
454
455bool ScopedThread::TryLock(const UserMutex &m) {
456  Event event(Event::MUTEX_TRYLOCK, &m);
457  impl_->send(&event);
458  return event.res;
459}
460
461void ScopedThread::Unlock(const UserMutex &m) {
462  Event event(Event::MUTEX_UNLOCK, &m);
463  impl_->send(&event);
464}
465
466void ScopedThread::ReadLock(const UserMutex &m) {
467  Event event(Event::MUTEX_READLOCK, &m);
468  impl_->send(&event);
469}
470
471bool ScopedThread::TryReadLock(const UserMutex &m) {
472  Event event(Event::MUTEX_TRYREADLOCK, &m);
473  impl_->send(&event);
474  return event.res;
475}
476
477void ScopedThread::ReadUnlock(const UserMutex &m) {
478  Event event(Event::MUTEX_READUNLOCK, &m);
479  impl_->send(&event);
480}
481
482void ScopedThread::Memcpy(void *dst, const void *src, int size,
483                          bool expect_race) {
484  Event event(Event::MEMCPY, dst, (uptr)src, size);
485  if (expect_race)
486    event.ExpectReport(__tsan::ReportTypeRace);
487  impl_->send(&event);
488}
489
490void ScopedThread::Memset(void *dst, int val, int size,
491                          bool expect_race) {
492  Event event(Event::MEMSET, dst, val, size);
493  if (expect_race)
494    event.ExpectReport(__tsan::ReportTypeRace);
495  impl_->send(&event);
496}
497