• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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