brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.9 KiB · 8aa0813 Raw
497 lines · cpp
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-exception6//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 __tsan76 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#endif107  else if (type_ == RW)108    CHECK_EQ(__interceptor_pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);109  else110    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#endif130  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#endif142  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#endif154  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#endif167  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    MEMSET207  };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#else292    const int ErrCode = ECHRNG;293#endif294    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