1 /*
2 This file is part of Valgrind, a dynamic binary instrumentation
3 framework.
4
5 Copyright (C) 2008-2008 Google Inc
6 opensource@google.com
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 02111-1307, USA.
22
23 The GNU General Public License is contained in the file COPYING.
24 */
25
26 /* Author: Konstantin Serebryany <opensource@google.com>
27 Author: Timur Iskhodzhanov <opensource@google.com>
28
29 This file contains a set of demonstration tests for ThreadSanitizer.
30 */
31
32 #include <gtest/gtest.h>
33
34 #include "test_utils.h"
35
main(int argc,char ** argv)36 int main(int argc, char** argv) {
37 testing::InitGoogleTest(&argc, argv);
38 return RUN_ALL_TESTS();
39 }
40
41 namespace RaceReportDemoTest { // {{{1
42 Mutex mu1; // This Mutex guards var.
43 Mutex mu2; // This Mutex is not related to var.
44 int var; // GUARDED_BY(mu1)
45
Thread1()46 void Thread1() { // Runs in thread named 'test-thread-1'.
47 MutexLock lock(&mu1); // Correct Mutex.
48 var = 1;
49 }
50
Thread2()51 void Thread2() { // Runs in thread named 'test-thread-2'.
52 MutexLock lock(&mu2); // Wrong Mutex.
53 var = 2;
54 }
55
TEST(DemoTests,RaceReportDemoTest)56 TEST(DemoTests, RaceReportDemoTest) {
57 ANNOTATE_TRACE_MEMORY(&var);
58 var = 0;
59 MyThread t1(Thread1, NULL, "test-thread-1");
60 MyThread t2(Thread2, NULL, "test-thread-2");
61 t1.Start();
62 t2.Start();
63 t1.Join();
64 t2.Join();
65 }
66 } // namespace RaceReportDemoTest
67
68 // test302: Complex race which happens at least twice. {{{1
69 namespace test302 {
70 // In this test we have many different accesses to GLOB and only one access
71 // is not synchronized properly.
72 int GLOB = 0;
73
74 Mutex MU1;
75 Mutex MU2;
Worker()76 void Worker() {
77 for(int i = 0; i < 100; i++) {
78 switch(i % 4) {
79 case 0:
80 // This read is protected correctly.
81 MU1.Lock(); CHECK(GLOB >= 0); MU1.Unlock();
82 break;
83 case 1:
84 // Here we used the wrong lock! The reason of the race is here.
85 MU2.Lock(); CHECK(GLOB >= 0); MU2.Unlock();
86 break;
87 case 2:
88 // This read is protected correctly.
89 MU1.Lock(); CHECK(GLOB >= 0); MU1.Unlock();
90 break;
91 case 3:
92 // This write is protected correctly.
93 MU1.Lock(); GLOB++; MU1.Unlock();
94 break;
95 }
96 // sleep a bit so that the threads interleave
97 // and the race happens at least twice.
98 usleep(100);
99 }
100 }
101
TEST(DemoTests,test302)102 TEST(DemoTests, test302) {
103 printf("test302: Complex race that happens twice.\n");
104 MyThread t1(Worker), t2(Worker);
105 t1.Start();
106 t2.Start();
107 t1.Join(); t2.Join();
108 }
109 } // namespace test302
110
111
112 // test303: Need to trace the memory to understand the report. {{{1
113 namespace test303 {
114 int GLOB = 0;
115
116 Mutex MU;
Worker1()117 void Worker1() { CHECK(GLOB >= 0); }
Worker2()118 void Worker2() { MU.Lock(); GLOB=1; MU.Unlock();}
119
TEST(DemoTests,test303)120 TEST(DemoTests, test303) {
121 printf("test303: a race that needs annotations.\n");
122 ANNOTATE_TRACE_MEMORY(&GLOB);
123 MyThreadArray t(Worker1, Worker2);
124 t.Start();
125 t.Join();
126 }
127 } // namespace test303
128
129
130
131 // test304: Can not trace the memory, since it is a library object. {{{1
132 namespace test304 {
133 string *STR;
134 Mutex MU;
135
Worker1()136 void Worker1() {
137 sleep(0);
138 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
139 MU.Lock(); CHECK(STR->length() >= 4); MU.Unlock();
140 }
Worker2()141 void Worker2() {
142 sleep(1);
143 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
144 CHECK(STR->length() >= 4); // Unprotected!
145 }
Worker3()146 void Worker3() {
147 sleep(2);
148 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
149 MU.Lock(); CHECK(STR->length() >= 4); MU.Unlock();
150 }
Worker4()151 void Worker4() {
152 sleep(3);
153 ANNOTATE_CONDVAR_SIGNAL((void*)0xDEADBEAF);
154 MU.Lock(); *STR += " + a very very long string"; MU.Unlock();
155 }
156
TEST(DemoTests,test304)157 TEST(DemoTests, test304) {
158 STR = new string ("The String");
159 printf("test304: a race where memory tracing does not work.\n");
160 MyThreadArray t(Worker1, Worker2, Worker3, Worker4);
161 t.Start();
162 t.Join();
163
164 printf("%s\n", STR->c_str());
165 delete STR;
166 }
167 } // namespace test304
168
169
170
171 // test305: A bit more tricky: two locks used inconsistenly. {{{1
172 namespace test305 {
173 int GLOB = 0;
174
175 // In this test GLOB is protected by MU1 and MU2, but inconsistently.
176 // The TRACES observed by helgrind are:
177 // TRACE[1]: Access{T2/S2 wr} -> new State{Mod; #LS=2; #SS=1; T2/S2}
178 // TRACE[2]: Access{T4/S9 wr} -> new State{Mod; #LS=1; #SS=2; T2/S2, T4/S9}
179 // TRACE[3]: Access{T5/S13 wr} -> new State{Mod; #LS=1; #SS=3; T2/S2, T4/S9, T5/S13}
180 // TRACE[4]: Access{T6/S19 wr} -> new State{Mod; #LS=0; #SS=4; T2/S2, T4/S9, T5/S13, T6/S19}
181 //
182 // The guilty access is either Worker2() or Worker4(), depending on
183 // which mutex is supposed to protect GLOB.
184 Mutex MU1;
185 Mutex MU2;
Worker1()186 void Worker1() { MU1.Lock(); MU2.Lock(); GLOB=1; MU2.Unlock(); MU1.Unlock(); }
Worker2()187 void Worker2() { MU1.Lock(); GLOB=2; MU1.Unlock(); }
Worker3()188 void Worker3() { MU1.Lock(); MU2.Lock(); GLOB=3; MU2.Unlock(); MU1.Unlock(); }
Worker4()189 void Worker4() { MU2.Lock(); GLOB=4; MU2.Unlock(); }
190
TEST(DemoTests,test305)191 TEST(DemoTests, test305) {
192 ANNOTATE_TRACE_MEMORY(&GLOB);
193 printf("test305: simple race.\n");
194 MyThread t1(Worker1), t2(Worker2), t3(Worker3), t4(Worker4);
195 t1.Start(); usleep(100);
196 t2.Start(); usleep(100);
197 t3.Start(); usleep(100);
198 t4.Start(); usleep(100);
199 t1.Join(); t2.Join(); t3.Join(); t4.Join();
200 }
201 } // namespace test305
202
203 // test306: Two locks are used to protect a var. {{{1
204 namespace test306 {
205 int GLOB = 0;
206 // Thread1 and Thread2 access the var under two locks.
207 // Thread3 uses no locks.
208
209 Mutex MU1;
210 Mutex MU2;
Worker1()211 void Worker1() { MU1.Lock(); MU2.Lock(); GLOB=1; MU2.Unlock(); MU1.Unlock(); }
Worker2()212 void Worker2() { MU1.Lock(); MU2.Lock(); GLOB=3; MU2.Unlock(); MU1.Unlock(); }
Worker3()213 void Worker3() { GLOB=4; }
214
TEST(DemoTests,test306)215 TEST(DemoTests, test306) {
216 ANNOTATE_TRACE_MEMORY(&GLOB);
217 printf("test306: simple race.\n");
218 MyThread t1(Worker1), t2(Worker2), t3(Worker3);
219 t1.Start(); usleep(100);
220 t2.Start(); usleep(100);
221 t3.Start(); usleep(100);
222 t1.Join(); t2.Join(); t3.Join();
223 }
224 } // namespace test306
225
226 // test307: Simple race, code with control flow {{{1
227 namespace test307 {
228 int *GLOB = 0;
229 volatile /*to fake the compiler*/ bool some_condition = true;
230
231
SomeFunc()232 void SomeFunc() { }
233
FunctionWithControlFlow()234 int FunctionWithControlFlow() {
235 int unrelated_stuff = 0;
236 unrelated_stuff++;
237 SomeFunc(); // "--keep-history=1" will point somewhere here.
238 if (some_condition) { // Or here
239 if (some_condition) {
240 unrelated_stuff++; // Or here.
241 unrelated_stuff++;
242 (*GLOB)++; // "--keep-history=2" will point here (experimental).
243 }
244 }
245 usleep(100000);
246 return unrelated_stuff;
247 }
248
Worker1()249 void Worker1() { FunctionWithControlFlow(); }
Worker2()250 void Worker2() { Worker1(); }
Worker3()251 void Worker3() { Worker2(); }
Worker4()252 void Worker4() { Worker3(); }
253
TEST(DemoTests,test307)254 TEST(DemoTests, test307) {
255 GLOB = new int;
256 *GLOB = 1;
257 printf("test307: simple race, code with control flow\n");
258 MyThreadArray t1(Worker1, Worker2, Worker3, Worker4);
259 t1.Start();
260 t1.Join();
261 }
262 } // namespace test307
263
264 // test308: Example of double-checked-locking {{{1
265 namespace test308 {
266 struct Foo {
267 int a;
268 };
269
270 static int is_inited = 0;
271 static Mutex lock;
272 static Foo *foo;
273
InitMe()274 void InitMe() {
275 if (!is_inited) {
276 lock.Lock();
277 if (!is_inited) {
278 foo = new Foo;
279 foo->a = 42;
280 is_inited = 1;
281 }
282 lock.Unlock();
283 }
284 }
285
UseMe()286 void UseMe() {
287 InitMe();
288 CHECK(foo && foo->a == 42);
289 }
290
Worker1()291 void Worker1() { UseMe(); }
Worker2()292 void Worker2() { UseMe(); }
Worker3()293 void Worker3() { UseMe(); }
294
295
TEST(DemoTests,test308)296 TEST(DemoTests, test308) {
297 ANNOTATE_TRACE_MEMORY(&is_inited);
298 printf("test308: Example of double-checked-locking\n");
299 MyThreadArray t1(Worker1, Worker2, Worker3);
300 t1.Start();
301 t1.Join();
302 }
303 } // namespace test308
304
305 // test309: Simple race on an STL object. {{{1
306 namespace test309 {
307 string GLOB;
308
Worker1()309 void Worker1() {
310 GLOB="Thread1";
311 }
Worker2()312 void Worker2() {
313 usleep(100000);
314 GLOB="Booooooooooo";
315 }
316
TEST(DemoTests,test309)317 TEST(DemoTests, test309) {
318 printf("test309: simple race on an STL object.\n");
319 MyThread t1(Worker1), t2(Worker2);
320 t1.Start();
321 t2.Start();
322 t1.Join(); t2.Join();
323 }
324 } // namespace test309
325
326 // test310: One more simple race. {{{1
327 namespace test310 {
328 int *PTR = NULL; // GUARDED_BY(mu1)
329
330 Mutex mu1; // Protects PTR.
331 Mutex mu2; // Unrelated to PTR.
332 Mutex mu3; // Unrelated to PTR.
333
Writer1()334 void Writer1() {
335 MutexLock lock3(&mu3); // This lock is unrelated to PTR.
336 MutexLock lock1(&mu1); // Protect PTR.
337 *PTR = 1;
338 }
339
Writer2()340 void Writer2() {
341 MutexLock lock2(&mu2); // This lock is unrelated to PTR.
342 MutexLock lock1(&mu1); // Protect PTR.
343 int some_unrelated_stuff = 0;
344 if (some_unrelated_stuff == 0)
345 some_unrelated_stuff++;
346 *PTR = 2;
347 }
348
349
Reader()350 void Reader() {
351 MutexLock lock2(&mu2); // Oh, gosh, this is a wrong mutex!
352 CHECK(*PTR <= 2);
353 }
354
355 // Some functions to make the stack trace non-trivial.
DoWrite1()356 void DoWrite1() { Writer1(); }
Thread1()357 void Thread1() { DoWrite1(); }
358
DoWrite2()359 void DoWrite2() { Writer2(); }
Thread2()360 void Thread2() { DoWrite2(); }
361
DoRead()362 void DoRead() { Reader(); }
Thread3()363 void Thread3() { DoRead(); }
364
TEST(DemoTests,test310)365 TEST(DemoTests, test310) {
366 printf("test310: simple race.\n");
367 PTR = new int;
368 ANNOTATE_TRACE_MEMORY(PTR);
369 *PTR = 0;
370 MyThread t1(Thread1, NULL, "writer1"),
371 t2(Thread2, NULL, "writer2"),
372 t3(Thread3, NULL, "buggy reader");
373 t1.Start();
374 t2.Start();
375 usleep(100000); // Let the writers go first.
376 t3.Start();
377
378 t1.Join();
379 t2.Join();
380 t3.Join();
381 }
382 } // namespace test310
383
384 // test311: Yet another simple race. {{{1
385 namespace test311 {
386 int *PTR = NULL; // GUARDED_BY(mu1)
387
388 Mutex mu1; // Protects PTR.
389 Mutex mu2; // Unrelated to PTR.
390 Mutex mu3; // Unrelated to PTR.
391
GoodWriter1()392 void GoodWriter1() { // Runs in Thread1
393 MutexLock lock3(&mu3); // This lock is unrelated to PTR.
394 MutexLock lock1(&mu1); // Protect PTR.
395 *PTR = 1;
396 }
397
GoodWriter2()398 void GoodWriter2() { // Runs in Thread2
399 MutexLock lock2(&mu2); // This lock is unrelated to PTR.
400 MutexLock lock1(&mu1); // Protect PTR.
401 *PTR = 2;
402 }
403
GoodReader()404 void GoodReader() { // Runs in Thread3
405 MutexLock lock1(&mu1); // Protect PTR.
406 CHECK(*PTR >= 0);
407 }
408
BuggyWriter()409 void BuggyWriter() { // Runs in Thread4
410 MutexLock lock2(&mu2); // Wrong mutex!
411 *PTR = 3;
412 }
413
414 // Some functions to make the stack trace non-trivial.
DoWrite1()415 void DoWrite1() { GoodWriter1(); }
Thread1()416 void Thread1() { DoWrite1(); }
417
DoWrite2()418 void DoWrite2() { GoodWriter2(); }
Thread2()419 void Thread2() { DoWrite2(); }
420
DoGoodRead()421 void DoGoodRead() { GoodReader(); }
Thread3()422 void Thread3() { DoGoodRead(); }
423
DoBadWrite()424 void DoBadWrite() { BuggyWriter(); }
Thread4()425 void Thread4() { DoBadWrite(); }
426
TEST(DemoTests,test311)427 TEST(DemoTests, test311) {
428 printf("test311: simple race.\n");
429 PTR = new int;
430 ANNOTATE_TRACE_MEMORY(PTR);
431 *PTR = 0;
432 MyThread t1(Thread1, NULL, "good writer1"),
433 t2(Thread2, NULL, "good writer2"),
434 t3(Thread3, NULL, "good reader"),
435 t4(Thread4, NULL, "buggy writer");
436 t1.Start();
437 t3.Start();
438 // t2 goes after t3. This way a pure happens-before detector has no chance.
439 usleep(10000);
440 t2.Start();
441 usleep(100000); // Let the good folks go first.
442 t4.Start();
443
444 t1.Join();
445 t2.Join();
446 t3.Join();
447 t4.Join();
448 }
449 } // namespace test311
450
451 // test312: A test with a very deep stack. {{{1
452 namespace test312 {
453 int GLOB = 0;
RaceyWrite()454 void RaceyWrite() { GLOB++; }
Func1()455 void Func1() { RaceyWrite(); }
Func2()456 void Func2() { Func1(); }
Func3()457 void Func3() { Func2(); }
Func4()458 void Func4() { Func3(); }
Func5()459 void Func5() { Func4(); }
Func6()460 void Func6() { Func5(); }
Func7()461 void Func7() { Func6(); }
Func8()462 void Func8() { Func7(); }
Func9()463 void Func9() { Func8(); }
Func10()464 void Func10() { Func9(); }
Func11()465 void Func11() { Func10(); }
Func12()466 void Func12() { Func11(); }
Func13()467 void Func13() { Func12(); }
Func14()468 void Func14() { Func13(); }
Func15()469 void Func15() { Func14(); }
Func16()470 void Func16() { Func15(); }
Func17()471 void Func17() { Func16(); }
Func18()472 void Func18() { Func17(); }
Func19()473 void Func19() { Func18(); }
Worker()474 void Worker() { Func19(); }
TEST(DemoTests,test312)475 TEST(DemoTests, test312) {
476 printf("test312: simple race with deep stack.\n");
477 MyThreadArray t(Worker, Worker, Worker);
478 t.Start();
479 t.Join();
480 }
481 } // namespace test312
482
483 // test313 TP: test for thread graph output {{{1
484 namespace test313 {
485 BlockingCounter *blocking_counter;
486 int GLOB = 0;
487
488 // Worker(N) will do 2^N increments of GLOB, each increment in a separate thread
Worker(int depth)489 void Worker(int depth) {
490 CHECK(depth >= 0);
491 if (depth > 0) {
492 ThreadPool pool(2);
493 pool.StartWorkers();
494 pool.Add(NewCallback(Worker, depth-1));
495 pool.Add(NewCallback(Worker, depth-1));
496 } else {
497 GLOB++; // Race here
498 }
499 }
TEST(DemoTests,test313)500 TEST(DemoTests, test313) {
501 printf("test313: positive\n");
502 Worker(4);
503 printf("\tGLOB=%d\n", GLOB);
504 }
505 } // namespace test313
506
507 // test314: minimalistic test for race in vptr. {{{1
508 namespace test314 {
509 // Race on vptr. Will run A::F() or B::F() depending on the timing.
510 class A {
511 public:
A()512 A() : done_(false) { }
F()513 virtual void F() {
514 printf ("A::F()\n");
515 }
Done()516 void Done() {
517 MutexLock lock(&mu_);
518 done_ = true;
519 }
~A()520 virtual ~A() {
521 while (true) {
522 MutexLock lock(&mu_);
523 if (done_) break;
524 }
525 }
526 private:
527 Mutex mu_;
528 bool done_;
529 };
530
531 class B : public A {
532 public:
F()533 virtual void F() {
534 printf ("B::F()\n");
535 }
536 };
537
538 static A *a;
539
Thread1()540 void Thread1() {
541 a->F();
542 a->Done();
543 };
544
Thread2()545 void Thread2() {
546 delete a;
547 }
TEST(DemoTests,test314)548 TEST(DemoTests, test314) {
549 printf("test314: race on vptr; May print A::F() or B::F().\n");
550 { // Will print B::F()
551 a = new B;
552 MyThreadArray t(Thread1, Thread2);
553 t.Start();
554 t.Join();
555 }
556 { // Will print A::F()
557 a = new B;
558 MyThreadArray t(Thread2, Thread1);
559 t.Start();
560 t.Join();
561 }
562 }
563 } // namespace test314
564
565 // test315: demo for hybrid's false positive. {{{1
566 namespace test315 {
567 int GLOB;
568 Mutex mu;
569 int flag;
570
Thread1()571 void Thread1() {
572 sleep(1);
573 mu.Lock();
574 bool f = flag;
575 mu.Unlock();
576 if (f) {
577 GLOB++;
578 }
579 }
580
Thread2()581 void Thread2() {
582 GLOB++;
583 mu.Lock();
584 flag = true;
585 mu.Unlock();
586 }
587
TEST(DemoTests,test315)588 TEST(DemoTests, test315) {
589 GLOB = 0;
590 printf("test315: false positive of the hybrid state machine\n");
591 MyThreadArray t(Thread1, Thread2);
592 t.Start();
593 t.Join();
594 }
595 } // namespace test315
596