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