1 //===-- tsan_sync_test.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_sync.h" 13 #include "tsan_rtl.h" 14 #include "gtest/gtest.h" 15 16 namespace __tsan { 17 18 TEST(MetaMap, Basic) { 19 ThreadState *thr = cur_thread(); 20 MetaMap *m = &ctx->metamap; 21 u64 block[1] = {}; // fake malloc block 22 m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64)); 23 MBlock *mb = m->GetBlock((uptr)&block[0]); 24 EXPECT_NE(mb, (MBlock*)0); 25 EXPECT_EQ(mb->siz, 1 * sizeof(u64)); 26 EXPECT_EQ(mb->tid, thr->tid); 27 uptr sz = m->FreeBlock(thr->proc(), (uptr)&block[0]); 28 EXPECT_EQ(sz, 1 * sizeof(u64)); 29 mb = m->GetBlock((uptr)&block[0]); 30 EXPECT_EQ(mb, (MBlock*)0); 31 } 32 33 TEST(MetaMap, FreeRange) { 34 ThreadState *thr = cur_thread(); 35 MetaMap *m = &ctx->metamap; 36 u64 block[4] = {}; // fake malloc block 37 m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64)); 38 m->AllocBlock(thr, 0, (uptr)&block[1], 3 * sizeof(u64)); 39 MBlock *mb1 = m->GetBlock((uptr)&block[0]); 40 EXPECT_EQ(mb1->siz, 1 * sizeof(u64)); 41 MBlock *mb2 = m->GetBlock((uptr)&block[1]); 42 EXPECT_EQ(mb2->siz, 3 * sizeof(u64)); 43 m->FreeRange(thr->proc(), (uptr)&block[0], 4 * sizeof(u64)); 44 mb1 = m->GetBlock((uptr)&block[0]); 45 EXPECT_EQ(mb1, (MBlock*)0); 46 mb2 = m->GetBlock((uptr)&block[1]); 47 EXPECT_EQ(mb2, (MBlock*)0); 48 } 49 50 TEST(MetaMap, Sync) NO_THREAD_SAFETY_ANALYSIS { 51 // EXPECT can call memset/etc. Disable interceptors to prevent 52 // them from detecting that we exit runtime with mutexes held. 53 ScopedIgnoreInterceptors ignore; 54 ThreadState *thr = cur_thread(); 55 MetaMap *m = &ctx->metamap; 56 u64 block[4] = {}; // fake malloc block 57 m->AllocBlock(thr, 0, (uptr)&block[0], 4 * sizeof(u64)); 58 SyncVar *s1 = m->GetIfExistsAndLock((uptr)&block[0], true); 59 EXPECT_EQ(s1, (SyncVar*)0); 60 s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true); 61 EXPECT_NE(s1, (SyncVar*)0); 62 EXPECT_EQ(s1->addr, (uptr)&block[0]); 63 s1->mtx.Unlock(); 64 SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block[1], false); 65 EXPECT_NE(s2, (SyncVar*)0); 66 EXPECT_EQ(s2->addr, (uptr)&block[1]); 67 s2->mtx.ReadUnlock(); 68 m->FreeBlock(thr->proc(), (uptr)&block[0]); 69 s1 = m->GetIfExistsAndLock((uptr)&block[0], true); 70 EXPECT_EQ(s1, (SyncVar*)0); 71 s2 = m->GetIfExistsAndLock((uptr)&block[1], true); 72 EXPECT_EQ(s2, (SyncVar*)0); 73 m->OnProcIdle(thr->proc()); 74 } 75 76 TEST(MetaMap, MoveMemory) NO_THREAD_SAFETY_ANALYSIS { 77 ScopedIgnoreInterceptors ignore; 78 ThreadState *thr = cur_thread(); 79 MetaMap *m = &ctx->metamap; 80 u64 block1[4] = {}; // fake malloc block 81 u64 block2[4] = {}; // fake malloc block 82 m->AllocBlock(thr, 0, (uptr)&block1[0], 3 * sizeof(u64)); 83 m->AllocBlock(thr, 0, (uptr)&block1[3], 1 * sizeof(u64)); 84 SyncVar *s1 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[0], true); 85 s1->mtx.Unlock(); 86 SyncVar *s2 = m->GetOrCreateAndLock(thr, 0, (uptr)&block1[1], true); 87 s2->mtx.Unlock(); 88 m->MoveMemory((uptr)&block1[0], (uptr)&block2[0], 4 * sizeof(u64)); 89 MBlock *mb1 = m->GetBlock((uptr)&block1[0]); 90 EXPECT_EQ(mb1, (MBlock*)0); 91 MBlock *mb2 = m->GetBlock((uptr)&block1[3]); 92 EXPECT_EQ(mb2, (MBlock*)0); 93 mb1 = m->GetBlock((uptr)&block2[0]); 94 EXPECT_NE(mb1, (MBlock*)0); 95 EXPECT_EQ(mb1->siz, 3 * sizeof(u64)); 96 mb2 = m->GetBlock((uptr)&block2[3]); 97 EXPECT_NE(mb2, (MBlock*)0); 98 EXPECT_EQ(mb2->siz, 1 * sizeof(u64)); 99 s1 = m->GetIfExistsAndLock((uptr)&block1[0], true); 100 EXPECT_EQ(s1, (SyncVar*)0); 101 s2 = m->GetIfExistsAndLock((uptr)&block1[1], true); 102 EXPECT_EQ(s2, (SyncVar*)0); 103 s1 = m->GetIfExistsAndLock((uptr)&block2[0], true); 104 EXPECT_NE(s1, (SyncVar*)0); 105 EXPECT_EQ(s1->addr, (uptr)&block2[0]); 106 s1->mtx.Unlock(); 107 s2 = m->GetIfExistsAndLock((uptr)&block2[1], true); 108 EXPECT_NE(s2, (SyncVar*)0); 109 EXPECT_EQ(s2->addr, (uptr)&block2[1]); 110 s2->mtx.Unlock(); 111 m->FreeRange(thr->proc(), (uptr)&block2[0], 4 * sizeof(u64)); 112 } 113 114 TEST(MetaMap, ResetSync) NO_THREAD_SAFETY_ANALYSIS { 115 ScopedIgnoreInterceptors ignore; 116 ThreadState *thr = cur_thread(); 117 MetaMap *m = &ctx->metamap; 118 u64 block[1] = {}; // fake malloc block 119 m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64)); 120 SyncVar *s = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true); 121 s->Reset(thr->proc()); 122 s->mtx.Unlock(); 123 uptr sz = m->FreeBlock(thr->proc(), (uptr)&block[0]); 124 EXPECT_EQ(sz, 1 * sizeof(u64)); 125 } 126 127 } // namespace __tsan 128