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