@@ -22,102 +22,115 @@ using namespace v3;
22
22
23
23
// We need to run all trace tests in a new thread,
24
24
// so that the thread trace is empty initially.
25
- static void run_in_thread (void *(*f)(void *), void *arg = nullptr) {
26
- pthread_t th;
27
- pthread_create (&th, nullptr , f, arg);
28
- pthread_join (th, nullptr );
29
- }
30
-
31
- #if SANITIZER_MAC
32
- // These tests are currently failing on Mac.
33
- // See https://reviews.llvm.org/D107911 for more details.
34
- # define MAYBE_RestoreAccess DISABLED_RestoreAccess
35
- # define MAYBE_MemoryAccessSize DISABLED_MemoryAccessSize
36
- # define MAYBE_RestoreMutexLock DISABLED_RestoreMutexLock
37
- # define MAYBE_MultiPart DISABLED_MultiPart
38
- #else
39
- # define MAYBE_RestoreAccess RestoreAccess
40
- # define MAYBE_MemoryAccessSize MemoryAccessSize
41
- # define MAYBE_RestoreMutexLock RestoreMutexLock
42
- # define MAYBE_MultiPart MultiPart
43
- #endif
25
+ template <uptr N>
26
+ struct ThreadArray {
27
+ ThreadArray () {
28
+ for (auto *&thr : threads) {
29
+ thr = static_cast <ThreadState *>(
30
+ MmapOrDie (sizeof (ThreadState), " ThreadState" ));
31
+ Tid tid = ThreadCreate (cur_thread (), 0 , 0 , true );
32
+ Processor *proc = ProcCreate ();
33
+ ProcWire (proc, thr);
34
+ ThreadStart (thr, tid, 0 , ThreadType::Regular);
35
+ }
36
+ }
44
37
45
- TEST (Trace, MAYBE_RestoreAccess) {
46
- struct Thread {
47
- static void *Func (void *arg) {
48
- // A basic test with some function entry/exit events,
49
- // some mutex lock/unlock events and some other distracting
50
- // memory events.
51
- ThreadState *thr = cur_thread ();
52
- TraceFunc (thr, 0x1000 );
53
- TraceFunc (thr, 0x1001 );
54
- TraceMutexLock (thr, v3::EventType::kLock , 0x4000 , 0x5000 , 0x6000 );
55
- TraceMutexLock (thr, v3::EventType::kLock , 0x4001 , 0x5001 , 0x6001 );
56
- TraceMutexUnlock (thr, 0x5000 );
57
- TraceFunc (thr);
58
- CHECK (TryTraceMemoryAccess (thr, 0x2001 , 0x3001 , 8 , kAccessRead ));
59
- TraceMutexLock (thr, v3::EventType::kRLock , 0x4002 , 0x5002 , 0x6002 );
60
- TraceFunc (thr, 0x1002 );
61
- CHECK (TryTraceMemoryAccess (thr, 0x2000 , 0x3000 , 8 , kAccessRead ));
62
- // This is the access we want to find.
63
- // The previous one is equivalent, but RestoreStack must prefer
64
- // the last of the matchig accesses.
65
- CHECK (TryTraceMemoryAccess (thr, 0x2002 , 0x3000 , 8 , kAccessRead ));
66
- Lock lock1 (&ctx->slot_mtx );
67
- ThreadRegistryLock lock2 (&ctx->thread_registry );
68
- VarSizeStackTrace stk;
69
- MutexSet mset;
70
- uptr tag = kExternalTagNone ;
71
- bool res =
72
- RestoreStack (thr->tid , v3::EventType::kAccessExt , thr->sid ,
73
- thr->epoch , 0x3000 , 8 , kAccessRead , &stk, &mset, &tag);
74
- CHECK (res);
75
- CHECK_EQ (stk.size , 3 );
76
- CHECK_EQ (stk.trace [0 ], 0x1000 );
77
- CHECK_EQ (stk.trace [1 ], 0x1002 );
78
- CHECK_EQ (stk.trace [2 ], 0x2002 );
79
- CHECK_EQ (mset.Size (), 2 );
80
- CHECK_EQ (mset.Get (0 ).addr , 0x5001 );
81
- CHECK_EQ (mset.Get (0 ).stack_id , 0x6001 );
82
- CHECK_EQ (mset.Get (0 ).write , true );
83
- CHECK_EQ (mset.Get (1 ).addr , 0x5002 );
84
- CHECK_EQ (mset.Get (1 ).stack_id , 0x6002 );
85
- CHECK_EQ (mset.Get (1 ).write , false );
86
- CHECK_EQ (tag, kExternalTagNone );
87
- return nullptr ;
38
+ ~ThreadArray () {
39
+ for (uptr i = 0 ; i < N; i++) {
40
+ if (threads[i])
41
+ Finish (i);
88
42
}
89
- };
90
- run_in_thread (Thread::Func);
43
+ }
44
+
45
+ void Finish (uptr i) {
46
+ auto *thr = threads[i];
47
+ threads[i] = nullptr ;
48
+ Processor *proc = thr->proc ();
49
+ ThreadFinish (thr);
50
+ ProcUnwire (proc, thr);
51
+ ProcDestroy (proc);
52
+ UnmapOrDie (thr, sizeof (ThreadState));
53
+ }
54
+
55
+ ThreadState *threads[N];
56
+ ThreadState *operator [](uptr i) { return threads[i]; }
57
+ ThreadState *operator ->() { return threads[0 ]; }
58
+ operator ThreadState *() { return threads[0 ]; }
59
+ };
60
+
61
+ TEST (Trace, RestoreAccess) {
62
+ // A basic test with some function entry/exit events,
63
+ // some mutex lock/unlock events and some other distracting
64
+ // memory events.
65
+ ThreadArray<1 > thr;
66
+ TraceFunc (thr, 0x1000 );
67
+ TraceFunc (thr, 0x1001 );
68
+ TraceMutexLock (thr, v3::EventType::kLock , 0x4000 , 0x5000 , 0x6000 );
69
+ TraceMutexLock (thr, v3::EventType::kLock , 0x4001 , 0x5001 , 0x6001 );
70
+ TraceMutexUnlock (thr, 0x5000 );
71
+ TraceFunc (thr);
72
+ CHECK (TryTraceMemoryAccess (thr, 0x2001 , 0x3001 , 8 , kAccessRead ));
73
+ TraceMutexLock (thr, v3::EventType::kRLock , 0x4002 , 0x5002 , 0x6002 );
74
+ TraceFunc (thr, 0x1002 );
75
+ CHECK (TryTraceMemoryAccess (thr, 0x2000 , 0x3000 , 8 , kAccessRead ));
76
+ // This is the access we want to find.
77
+ // The previous one is equivalent, but RestoreStack must prefer
78
+ // the last of the matchig accesses.
79
+ CHECK (TryTraceMemoryAccess (thr, 0x2002 , 0x3000 , 8 , kAccessRead ));
80
+ Lock lock1 (&ctx->slot_mtx );
81
+ ThreadRegistryLock lock2 (&ctx->thread_registry );
82
+ VarSizeStackTrace stk;
83
+ MutexSet mset;
84
+ uptr tag = kExternalTagNone ;
85
+ bool res =
86
+ RestoreStack (thr->tid , v3::EventType::kAccessExt , thr->sid , thr->epoch ,
87
+ 0x3000 , 8 , kAccessRead , &stk, &mset, &tag);
88
+ CHECK (res);
89
+ CHECK_EQ (stk.size , 3 );
90
+ CHECK_EQ (stk.trace [0 ], 0x1000 );
91
+ CHECK_EQ (stk.trace [1 ], 0x1002 );
92
+ CHECK_EQ (stk.trace [2 ], 0x2002 );
93
+ CHECK_EQ (mset.Size (), 2 );
94
+ CHECK_EQ (mset.Get (0 ).addr , 0x5001 );
95
+ CHECK_EQ (mset.Get (0 ).stack_id , 0x6001 );
96
+ CHECK_EQ (mset.Get (0 ).write , true );
97
+ CHECK_EQ (mset.Get (1 ).addr , 0x5002 );
98
+ CHECK_EQ (mset.Get (1 ).stack_id , 0x6002 );
99
+ CHECK_EQ (mset.Get (1 ).write , false );
100
+ CHECK_EQ (tag, kExternalTagNone );
91
101
}
92
102
93
- TEST (Trace, MAYBE_MemoryAccessSize) {
94
- struct Thread {
95
- struct Params {
96
- uptr access_size, offset, size;
97
- bool res;
98
- int type;
99
- };
100
- static void *Func (void *arg) {
101
- // Test tracing and matching of accesses of different sizes.
102
- const Params *params = static_cast <Params *>(arg);
103
+ TEST (Trace, MemoryAccessSize) {
104
+ // Test tracing and matching of accesses of different sizes.
105
+ struct Params {
106
+ uptr access_size, offset, size;
107
+ bool res;
108
+ };
109
+ Params tests[] = {
110
+ {1 , 0 , 1 , true }, {4 , 0 , 2 , true },
111
+ {4 , 2 , 2 , true }, {8 , 3 , 1 , true },
112
+ {2 , 1 , 1 , true }, {1 , 1 , 1 , false },
113
+ {8 , 5 , 4 , false }, {4 , static_cast <uptr>(-1l ), 4 , false },
114
+ };
115
+ for (auto params : tests) {
116
+ for (int type = 0 ; type < 3 ; type++) {
117
+ ThreadArray<1 > thr;
103
118
Printf (" access_size=%zu, offset=%zu, size=%zu, res=%d, type=%d\n " ,
104
- params->access_size , params->offset , params->size , params->res ,
105
- params->type );
106
- ThreadState *thr = cur_thread ();
119
+ params.access_size , params.offset , params.size , params.res , type);
107
120
TraceFunc (thr, 0x1000 );
108
- switch (params-> type ) {
121
+ switch (type) {
109
122
case 0 :
110
123
// This should emit compressed event.
111
- CHECK (TryTraceMemoryAccess (thr, 0x2000 , 0x3000 , params-> access_size ,
124
+ CHECK (TryTraceMemoryAccess (thr, 0x2000 , 0x3000 , params. access_size ,
112
125
kAccessRead ));
113
126
break ;
114
127
case 1 :
115
128
// This should emit full event.
116
- CHECK (TryTraceMemoryAccess (thr, 0x2000000 , 0x3000 ,
117
- params-> access_size , kAccessRead ));
129
+ CHECK (TryTraceMemoryAccess (thr, 0x2000000 , 0x3000 , params. access_size ,
130
+ kAccessRead ));
118
131
break ;
119
132
case 2 :
120
- TraceMemoryAccessRange (thr, 0x2000000 , 0x3000 , params-> access_size ,
133
+ TraceMemoryAccessRange (thr, 0x2000000 , 0x3000 , params. access_size ,
121
134
kAccessRead );
122
135
break ;
123
136
}
@@ -127,105 +140,82 @@ TEST(Trace, MAYBE_MemoryAccessSize) {
127
140
MutexSet mset;
128
141
uptr tag = kExternalTagNone ;
129
142
bool res = RestoreStack (thr->tid , v3::EventType::kAccessExt , thr->sid ,
130
- thr->epoch , 0x3000 + params-> offset , params-> size ,
143
+ thr->epoch , 0x3000 + params. offset , params. size ,
131
144
kAccessRead , &stk, &mset, &tag);
132
- CHECK_EQ (res, params-> res );
133
- if (params-> res ) {
145
+ CHECK_EQ (res, params. res );
146
+ if (params. res ) {
134
147
CHECK_EQ (stk.size , 2 );
135
148
CHECK_EQ (stk.trace [0 ], 0x1000 );
136
- CHECK_EQ (stk.trace [1 ], params-> type ? 0x2000000 : 0x2000 );
149
+ CHECK_EQ (stk.trace [1 ], type ? 0x2000000 : 0x2000 );
137
150
}
138
- return nullptr ;
139
151
}
140
- };
141
- Thread::Params tests[] = {
142
- {1 , 0 , 1 , true , 0 }, {4 , 0 , 2 , true , 0 },
143
- {4 , 2 , 2 , true , 0 }, {8 , 3 , 1 , true , 0 },
144
- {2 , 1 , 1 , true , 0 }, {1 , 1 , 1 , false , 0 },
145
- {8 , 5 , 4 , false , 0 }, {4 , static_cast <uptr>(-1l ), 4 , false , 0 },
146
- };
147
- for (auto params : tests) {
148
- for (params.type = 0 ; params.type < 3 ; params.type ++)
149
- run_in_thread (Thread::Func, ¶ms);
150
152
}
151
153
}
152
154
153
- TEST (Trace, MAYBE_RestoreMutexLock) {
154
- struct Thread {
155
- static void *Func (void *arg) {
156
- // Check of restoration of a mutex lock event.
157
- ThreadState *thr = cur_thread ();
158
- TraceFunc (thr, 0x1000 );
159
- TraceMutexLock (thr, v3::EventType::kLock , 0x4000 , 0x5000 , 0x6000 );
160
- TraceMutexLock (thr, v3::EventType::kRLock , 0x4001 , 0x5001 , 0x6001 );
161
- TraceMutexLock (thr, v3::EventType::kRLock , 0x4002 , 0x5001 , 0x6002 );
162
- Lock lock1 (&ctx->slot_mtx );
163
- ThreadRegistryLock lock2 (&ctx->thread_registry );
164
- VarSizeStackTrace stk;
165
- MutexSet mset;
166
- uptr tag = kExternalTagNone ;
167
- bool res = RestoreStack (thr->tid , v3::EventType::kLock , thr->sid ,
168
- thr->epoch , 0x5001 , 0 , 0 , &stk, &mset, &tag);
169
- CHECK (res);
170
- CHECK_EQ (stk.size , 2 );
171
- CHECK_EQ (stk.trace [0 ], 0x1000 );
172
- CHECK_EQ (stk.trace [1 ], 0x4002 );
173
- CHECK_EQ (mset.Size (), 2 );
174
- CHECK_EQ (mset.Get (0 ).addr , 0x5000 );
175
- CHECK_EQ (mset.Get (0 ).stack_id , 0x6000 );
176
- CHECK_EQ (mset.Get (0 ).write , true );
177
- CHECK_EQ (mset.Get (1 ).addr , 0x5001 );
178
- CHECK_EQ (mset.Get (1 ).stack_id , 0x6001 );
179
- CHECK_EQ (mset.Get (1 ).write , false );
180
- return nullptr ;
181
- }
182
- };
183
- run_in_thread (Thread::Func);
155
+ TEST (Trace, RestoreMutexLock) {
156
+ // Check of restoration of a mutex lock event.
157
+ ThreadArray<1 > thr;
158
+ TraceFunc (thr, 0x1000 );
159
+ TraceMutexLock (thr, v3::EventType::kLock , 0x4000 , 0x5000 , 0x6000 );
160
+ TraceMutexLock (thr, v3::EventType::kRLock , 0x4001 , 0x5001 , 0x6001 );
161
+ TraceMutexLock (thr, v3::EventType::kRLock , 0x4002 , 0x5001 , 0x6002 );
162
+ Lock lock1 (&ctx->slot_mtx );
163
+ ThreadRegistryLock lock2 (&ctx->thread_registry );
164
+ VarSizeStackTrace stk;
165
+ MutexSet mset;
166
+ uptr tag = kExternalTagNone ;
167
+ bool res = RestoreStack (thr->tid , v3::EventType::kLock , thr->sid , thr->epoch ,
168
+ 0x5001 , 0 , 0 , &stk, &mset, &tag);
169
+ CHECK (res);
170
+ CHECK_EQ (stk.size , 2 );
171
+ CHECK_EQ (stk.trace [0 ], 0x1000 );
172
+ CHECK_EQ (stk.trace [1 ], 0x4002 );
173
+ CHECK_EQ (mset.Size (), 2 );
174
+ CHECK_EQ (mset.Get (0 ).addr , 0x5000 );
175
+ CHECK_EQ (mset.Get (0 ).stack_id , 0x6000 );
176
+ CHECK_EQ (mset.Get (0 ).write , true );
177
+ CHECK_EQ (mset.Get (1 ).addr , 0x5001 );
178
+ CHECK_EQ (mset.Get (1 ).stack_id , 0x6001 );
179
+ CHECK_EQ (mset.Get (1 ).write , false );
184
180
}
185
181
186
- TEST (Trace, MAYBE_MultiPart) {
187
- struct Thread {
188
- static void *Func (void *arg) {
189
- // Check replay of a trace with multiple parts.
190
- ThreadState *thr = cur_thread ();
191
- TraceFunc (thr, 0x1000 );
192
- TraceFunc (thr, 0x2000 );
193
- TraceMutexLock (thr, v3::EventType::kLock , 0x4000 , 0x5000 , 0x6000 );
194
- const uptr kEvents = 3 * sizeof (TracePart) / sizeof (v3::Event);
195
- for (uptr i = 0 ; i < kEvents ; i++) {
196
- TraceFunc (thr, 0x3000 );
197
- TraceMutexLock (thr, v3::EventType::kLock , 0x4002 , 0x5002 , 0x6002 );
198
- TraceMutexUnlock (thr, 0x5002 );
199
- TraceFunc (thr);
200
- }
201
- TraceFunc (thr, 0x4000 );
202
- TraceMutexLock (thr, v3::EventType::kRLock , 0x4001 , 0x5001 , 0x6001 );
203
- CHECK (TryTraceMemoryAccess (thr, 0x2002 , 0x3000 , 8 , kAccessRead ));
204
- Lock lock1 (&ctx->slot_mtx );
205
- ThreadRegistryLock lock2 (&ctx->thread_registry );
206
- VarSizeStackTrace stk;
207
- MutexSet mset;
208
- uptr tag = kExternalTagNone ;
209
- bool res =
210
- RestoreStack (thr->tid , v3::EventType::kAccessExt , thr->sid ,
211
- thr->epoch , 0x3000 , 8 , kAccessRead , &stk, &mset, &tag);
212
- CHECK (res);
213
- CHECK_EQ (stk.size , 4 );
214
- CHECK_EQ (stk.trace [0 ], 0x1000 );
215
- CHECK_EQ (stk.trace [1 ], 0x2000 );
216
- CHECK_EQ (stk.trace [2 ], 0x4000 );
217
- CHECK_EQ (stk.trace [3 ], 0x2002 );
218
- CHECK_EQ (mset.Size (), 2 );
219
- CHECK_EQ (mset.Get (0 ).addr , 0x5000 );
220
- CHECK_EQ (mset.Get (0 ).stack_id , 0x6000 );
221
- CHECK_EQ (mset.Get (0 ).write , true );
222
- CHECK_EQ (mset.Get (1 ).addr , 0x5001 );
223
- CHECK_EQ (mset.Get (1 ).stack_id , 0x6001 );
224
- CHECK_EQ (mset.Get (1 ).write , false );
225
- return nullptr ;
226
- }
227
- };
228
- run_in_thread (Thread::Func);
182
+ TEST (Trace, MultiPart) {
183
+ // Check replay of a trace with multiple parts.
184
+ ThreadArray<1 > thr;
185
+ TraceFunc (thr, 0x1000 );
186
+ TraceFunc (thr, 0x2000 );
187
+ TraceMutexLock (thr, v3::EventType::kLock , 0x4000 , 0x5000 , 0x6000 );
188
+ const uptr kEvents = 3 * sizeof (TracePart) / sizeof (v3::Event);
189
+ for (uptr i = 0 ; i < kEvents ; i++) {
190
+ TraceFunc (thr, 0x3000 );
191
+ TraceMutexLock (thr, v3::EventType::kLock , 0x4002 , 0x5002 , 0x6002 );
192
+ TraceMutexUnlock (thr, 0x5002 );
193
+ TraceFunc (thr);
194
+ }
195
+ TraceFunc (thr, 0x4000 );
196
+ TraceMutexLock (thr, v3::EventType::kRLock , 0x4001 , 0x5001 , 0x6001 );
197
+ CHECK (TryTraceMemoryAccess (thr, 0x2002 , 0x3000 , 8 , kAccessRead ));
198
+ Lock lock1 (&ctx->slot_mtx );
199
+ ThreadRegistryLock lock2 (&ctx->thread_registry );
200
+ VarSizeStackTrace stk;
201
+ MutexSet mset;
202
+ uptr tag = kExternalTagNone ;
203
+ bool res =
204
+ RestoreStack (thr->tid , v3::EventType::kAccessExt , thr->sid , thr->epoch ,
205
+ 0x3000 , 8 , kAccessRead , &stk, &mset, &tag);
206
+ CHECK (res);
207
+ CHECK_EQ (stk.size , 4 );
208
+ CHECK_EQ (stk.trace [0 ], 0x1000 );
209
+ CHECK_EQ (stk.trace [1 ], 0x2000 );
210
+ CHECK_EQ (stk.trace [2 ], 0x4000 );
211
+ CHECK_EQ (stk.trace [3 ], 0x2002 );
212
+ CHECK_EQ (mset.Size (), 2 );
213
+ CHECK_EQ (mset.Get (0 ).addr , 0x5000 );
214
+ CHECK_EQ (mset.Get (0 ).stack_id , 0x6000 );
215
+ CHECK_EQ (mset.Get (0 ).write , true );
216
+ CHECK_EQ (mset.Get (1 ).addr , 0x5001 );
217
+ CHECK_EQ (mset.Get (1 ).stack_id , 0x6001 );
218
+ CHECK_EQ (mset.Get (1 ).write , false );
229
219
}
230
220
231
221
} // namespace __tsan
0 commit comments