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: Timur Iskhodzhanov <opensource@google.com>
27
28 This file contains a set of Windows-specific unit tests for
29 a data race detection tool.
30 */
31
32 #include <gtest/gtest.h>
33 #include "test_utils.h"
34 #include "gtest_fixture_injection.h"
35
DummyWorker()36 void DummyWorker() {
37 }
38
LongWorker()39 void LongWorker() {
40 Sleep(1);
41 volatile int i = 1 << 20;
42 while(i--);
43 }
44
WriteWorker(int * var)45 void WriteWorker(int *var) {
46 LongWorker();
47 *var = 42;
48 }
49
VeryLongWriteWorker(int * var)50 void VeryLongWriteWorker(int *var) {
51 Sleep(1000);
52 *var = 42;
53 }
54
TEST(NegativeTests,WindowsCreateThreadFailureTest)55 TEST(NegativeTests, WindowsCreateThreadFailureTest) { // {{{1
56 HANDLE t = ::CreateThread(0, -1,
57 (LPTHREAD_START_ROUTINE)DummyWorker, 0, 0, 0);
58 CHECK(t == 0);
59 }
60
TEST(NegativeTests,DISABLED_WindowsCreateThreadSuspendedTest)61 TEST(NegativeTests, DISABLED_WindowsCreateThreadSuspendedTest) { // {{{1
62 // Hangs under TSan, see
63 // http://code.google.com/p/data-race-test/issues/detail?id=61
64 int *var = new int;
65 HANDLE t = ::CreateThread(0, 0,
66 (LPTHREAD_START_ROUTINE)WriteWorker, var,
67 CREATE_SUSPENDED, 0);
68 CHECK(t > 0);
69 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(t, 200));
70 *var = 1;
71 EXPECT_EQ(1, ResumeThread(t));
72 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(t, INFINITE));
73 EXPECT_EQ(42, *var);
74 delete var;
75 }
76
TEST(NegativeTests,WindowsThreadStackSizeTest)77 TEST(NegativeTests, WindowsThreadStackSizeTest) { // {{{1
78 // Just spawn few threads with different stack sizes.
79 int sizes[3] = {1 << 19, 1 << 21, 1 << 22};
80 for (int i = 0; i < 3; i++) {
81 HANDLE t = ::CreateThread(0, sizes[i],
82 (LPTHREAD_START_ROUTINE)DummyWorker, 0, 0, 0);
83 CHECK(t > 0);
84 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(t, INFINITE));
85 CloseHandle(t);
86 }
87 }
88
TEST(NegativeTests,WindowsJoinWithTimeout)89 TEST(NegativeTests, WindowsJoinWithTimeout) { // {{{1
90 HANDLE t = ::CreateThread(0, 0,
91 (LPTHREAD_START_ROUTINE)LongWorker, 0, 0, 0);
92 ASSERT_TRUE(t > 0);
93 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(t, 1));
94 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(t, INFINITE));
95 CloseHandle(t);
96 }
97
TEST(NegativeTests,HappensBeforeOnThreadJoin)98 TEST(NegativeTests, HappensBeforeOnThreadJoin) { // {{{1
99 int *var = new int;
100 HANDLE t = ::CreateThread(0, 0,
101 (LPTHREAD_START_ROUTINE)WriteWorker, var, 0, 0);
102 ASSERT_TRUE(t > 0);
103 // Calling WaitForSingleObject two times to make sure the H-B arc
104 // is created on the second call. There was a bug that the thread handle
105 // was deleted even when WaitForSingleObject timed out.
106 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(t, 1));
107 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(t, INFINITE));
108 EXPECT_EQ(*var, 42);
109 CloseHandle(t);
110 delete var;
111 }
112
TEST(NegativeTests,HappensBeforeOnThreadJoinTidReuse)113 TEST(NegativeTests, HappensBeforeOnThreadJoinTidReuse) { // {{{1
114 HANDLE t1 = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)DummyWorker, 0, 0, 0);
115 CloseHandle(t1);
116 Sleep(1000);
117
118 int *var = new int;
119 HANDLE t2 = ::CreateThread(0, 0,
120 (LPTHREAD_START_ROUTINE)WriteWorker, var, 0, 0);
121 printf("t1 = %d, t2 = %d\n");
122 CHECK(t2 > 0);
123 CHECK(WAIT_OBJECT_0 == ::WaitForSingleObject(t2, INFINITE));
124 CHECK(*var == 42);
125 delete var;
126 }
127
TEST(NegativeTests,WaitForMultipleObjectsWaitAllTest)128 TEST(NegativeTests, WaitForMultipleObjectsWaitAllTest) {
129 int var1 = 13,
130 var2 = 13;
131 HANDLE t1 = ::CreateThread(0, 0,
132 (LPTHREAD_START_ROUTINE)WriteWorker, &var1, 0, 0),
133 t2 = ::CreateThread(0, 0,
134 (LPTHREAD_START_ROUTINE)WriteWorker, &var2, 0, 0);
135 ASSERT_TRUE(t1 > 0);
136 ASSERT_TRUE(t2 > 0);
137
138 HANDLE handles[2] = {t1, t2};
139 // Calling WaitForMultipleObjectsTest two times to make sure the H-B arc
140 // are created on the second call.
141 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForMultipleObjects(2, handles, TRUE, 1));
142 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(2, handles, TRUE, INFINITE));
143 EXPECT_EQ(var1, 42);
144 EXPECT_EQ(var2, 42);
145 CloseHandle(t1);
146 CloseHandle(t2);
147 }
148
TEST(NegativeTests,WaitForMultipleObjectsWaitOneTest)149 TEST(NegativeTests, WaitForMultipleObjectsWaitOneTest) {
150 int var1 = 13,
151 var2 = 13;
152 HANDLE t1 = ::CreateThread(0, 0,
153 (LPTHREAD_START_ROUTINE)VeryLongWriteWorker, &var1, 0, 0),
154 t2 = ::CreateThread(0, 0,
155 (LPTHREAD_START_ROUTINE)WriteWorker, &var2, 0, 0);
156 ASSERT_TRUE(t1 > 0);
157 ASSERT_TRUE(t2 > 0);
158
159 HANDLE handles[2] = {t1, t2};
160 // Calling WaitForMultipleObjectsTest two times to make sure the H-B arc
161 // are created on the second call.
162 EXPECT_EQ(WAIT_TIMEOUT, ::WaitForMultipleObjects(2, handles, FALSE, 1));
163 EXPECT_EQ(WAIT_OBJECT_0 + 1, ::WaitForMultipleObjects(2, handles, FALSE, INFINITE));
164 EXPECT_EQ(var2, 42);
165 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(1, handles, FALSE, INFINITE));
166 EXPECT_EQ(var1, 42);
167 CloseHandle(t1);
168 CloseHandle(t2);
169 }
170
171 namespace RegisterWaitForSingleObjectTest { // {{{1
172 StealthNotification *n = NULL;
173 HANDLE monitored_object = NULL;
174
SignalStealthNotification()175 void SignalStealthNotification() {
176 n->wait();
177 SetEvent(monitored_object);
178 }
179
foo()180 void foo() { }
181
DoneWaiting(void * param,BOOLEAN timed_out)182 void CALLBACK DoneWaiting(void *param, BOOLEAN timed_out) {
183 int *i = (int*)param;
184 foo(); // make sure this function has a call. See issue 24.
185 (*i)++;
186 }
187
TEST(NegativeTests,WindowsRegisterWaitForSingleObjectTest)188 TEST(NegativeTests, WindowsRegisterWaitForSingleObjectTest) { // {{{1
189 // These are very tricky false positive found while testing Chromium.
190 //
191 // Report #1:
192 // Everything after UnregisterWaitEx(*, INVALID_HANDLE_VALUE) happens-after
193 // execution of DoneWaiting callback. Currently, we don't catch this h-b.
194 //
195 // Report #2:
196 // The callback thread is re-used between Registet/Unregister/Register calls
197 // so we miss h-b between "int *obj = ..." and DoneWaiting on the second
198 // iteration.
199 for (int i = 0; i < 2; i++) {
200 n = new StealthNotification();
201 int *obj = new int(0);
202 HANDLE wait_object = NULL;
203
204 monitored_object = ::CreateEvent(NULL, false, false, NULL);
205 printf("monitored_object = %p\n", monitored_object);
206 MyThread mt(SignalStealthNotification);
207 mt.Start();
208 ANNOTATE_TRACE_MEMORY(obj);
209 CHECK(0 != ::RegisterWaitForSingleObject(&wait_object, monitored_object,
210 DoneWaiting, obj, INFINITE,
211 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE));
212 printf("wait_object = %p\n", wait_object);
213 n->signal();
214 mt.Join();
215 Sleep(1000);
216 CHECK(0 != ::UnregisterWaitEx(wait_object, INVALID_HANDLE_VALUE));
217 (*obj)++;
218 CHECK(*obj == 2);
219 CloseHandle(monitored_object);
220 delete n;
221 delete obj;
222 }
223 }
224 }
225
226 namespace QueueUserWorkItemTests {
Callback(void * param)227 DWORD CALLBACK Callback(void *param) {
228 int *ptr = (int*)param;
229 (*ptr)++;
230 delete ptr;
231 return 0;
232 }
233
TEST(NegativeTests,WindowsQueueUserWorkItemTest)234 TEST(NegativeTests, WindowsQueueUserWorkItemTest) {
235 // False positive:
236 // The callback thread is allocated from a thread pool and can be re-used.
237 // As a result, we may miss h-b between "int *obj = ..." and Callback execution.
238 for (int i = 0; i < 5; i++) {
239 int *obj = new int(0);
240 ANNOTATE_TRACE_MEMORY(obj);
241 CHECK(QueueUserWorkItem(Callback, obj, i % 2 ? WT_EXECUTELONGFUNCTION : 0));
242 Sleep(500);
243 }
244 }
245
246 int GLOB = 42;
247
Callback2(void * param)248 DWORD CALLBACK Callback2(void *param) {
249 StealthNotification *ptr = (StealthNotification*)param;
250 GLOB++;
251 Sleep(100);
252 ptr->signal();
253 return 0;
254 }
255
TEST(PositiveTests,WindowsQueueUserWorkItemTest)256 TEST(PositiveTests, WindowsQueueUserWorkItemTest) {
257 ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB, "PositiveTests.WindowsQueueUserWorkItemTest");
258
259 const int N_THREAD = 5;
260 StealthNotification n[N_THREAD];
261
262 for (int i = 0; i < N_THREAD; i++)
263 CHECK(QueueUserWorkItem(Callback2, &n[i], i % 2 ? WT_EXECUTELONGFUNCTION : 0));
264
265 for (int i = 0; i < N_THREAD; i++)
266 n[i].wait();
267 }
268 }
269
270 namespace WindowsCriticalSectionTest { // {{{1
271 CRITICAL_SECTION cs;
272
TEST(NegativeTests,WindowsCriticalSectionTest)273 TEST(NegativeTests, WindowsCriticalSectionTest) {
274 InitializeCriticalSection(&cs);
275 EnterCriticalSection(&cs);
276 TryEnterCriticalSection(&cs);
277 LeaveCriticalSection(&cs);
278 DeleteCriticalSection(&cs);
279 }
280 } // namespace
281
282
283 namespace WindowsSRWLockTest { // {{{1
284 #if WINVER >= 0x0600 // Vista or Windows Server 2000
285 SRWLOCK SRWLock;
286 int *obj;
287
Reader()288 void Reader() {
289 AcquireSRWLockShared(&SRWLock);
290 CHECK(*obj <= 2 && *obj >= 0);
291 ReleaseSRWLockShared(&SRWLock);
292 }
293
Writer()294 void Writer() {
295 AcquireSRWLockExclusive(&SRWLock);
296 (*obj)++;
297 ReleaseSRWLockExclusive(&SRWLock);
298 }
299
300 #if 0 // This doesn't work in older versions of Windows.
301 void TryReader() {
302 if (TryAcquireSRWLockShared(&SRWLock)) {
303 CHECK(*obj <= 2 && *obj >= 0);
304 ReleaseSRWLockShared(&SRWLock);
305 }
306 }
307
308 void TryWriter() {
309 if (TryAcquireSRWLockExclusive(&SRWLock)) {
310 (*obj)++;
311 ReleaseSRWLockExclusive(&SRWLock);
312 }
313 }
314 #endif
315
TEST(NegativeTests,WindowsSRWLockTest)316 TEST(NegativeTests, WindowsSRWLockTest) {
317 InitializeSRWLock(&SRWLock);
318 obj = new int(0);
319 ANNOTATE_TRACE_MEMORY(obj);
320 MyThreadArray t(Reader, Writer, Reader, Writer);
321 t.Start();
322 t.Join();
323 AcquireSRWLockShared(&SRWLock);
324 ReleaseSRWLockShared(&SRWLock);
325 CHECK(*obj == 2);
326 delete obj;
327 }
328
TEST(NegativeTests,WindowsSRWLockHackyInitializationTest)329 TEST(NegativeTests, WindowsSRWLockHackyInitializationTest) {
330 // A similar pattern has been found on Chromium media_unittests
331 InitializeSRWLock(&SRWLock);
332 AcquireSRWLockExclusive(&SRWLock);
333 // Leave the lock acquired
334
335 // Reset the lock
336 InitializeSRWLock(&SRWLock);
337 obj = new int(0);
338 MyThreadArray t(Reader, Writer, Reader, Writer);
339 t.Start();
340 t.Join();
341 delete obj;
342 }
343 #endif // WINVER >= 0x0600
344 } // namespace
345
346 namespace WindowsConditionVariableSRWTest { // {{{1
347 #if WINVER >= 0x0600 // Vista or Windows Server 2000
348 SRWLOCK SRWLock;
349 CONDITION_VARIABLE cv;
350 bool cond;
351 int *obj;
352
353 StealthNotification n;
354
WaiterSRW()355 void WaiterSRW() {
356 *obj = 1;
357 n.wait();
358 AcquireSRWLockExclusive(&SRWLock);
359 cond = true;
360 WakeConditionVariable(&cv);
361 ReleaseSRWLockExclusive(&SRWLock);
362 }
363
WakerSRW()364 void WakerSRW() {
365 AcquireSRWLockExclusive(&SRWLock);
366 n.signal();
367 while (!cond) {
368 SleepConditionVariableSRW(&cv, &SRWLock, 10, 0);
369 }
370 ReleaseSRWLockExclusive(&SRWLock);
371 CHECK(*obj == 1);
372 *obj = 2;
373 }
374
TEST(NegativeTests,WindowsConditionVariableSRWTest)375 TEST(NegativeTests, WindowsConditionVariableSRWTest) {
376 InitializeSRWLock(&SRWLock);
377 InitializeConditionVariable(&cv);
378 obj = new int(0);
379 cond = false;
380 ANNOTATE_TRACE_MEMORY(obj);
381 MyThreadArray t(WaiterSRW, WakerSRW);
382 t.Start();
383 t.Join();
384 CHECK(*obj == 2);
385 delete obj;
386 }
387 #endif // WINVER >= 0x0600
388 } // namespace
389
390
391 namespace WindowsInterlockedListTest { // {{{1
392 SLIST_HEADER list;
393
394 struct Item {
395 SLIST_ENTRY entry;
396 int foo;
397 };
398
Push()399 void Push() {
400 Item *item = new Item;
401 item->foo = 42;
402 InterlockedPushEntrySList(&list, (PSINGLE_LIST_ENTRY)item);
403 }
404
Pop()405 void Pop() {
406 Item *item;
407 while (0 == (item = (Item*)InterlockedPopEntrySList(&list))) {
408 Sleep(1);
409 }
410 CHECK(item->foo == 42);
411 delete item;
412 }
413
TEST(NegativeTests,WindowsInterlockedListTest)414 TEST(NegativeTests, WindowsInterlockedListTest) {
415 InitializeSListHead(&list);
416 MyThreadArray t(Push, Pop);
417 t.Start();
418 t.Join();
419 }
420
421 } // namespace
422
423 namespace FileSystemReports { // {{{1
424
425 // This is a test for the flaky report found in
426 // Chromium net_unittests.
427 //
428 // Looks like the test is sensitive to memory allocations / scheduling order,
429 // so you shouldn't run other tests while investigating the issue.
430 // The report is ~50% flaky.
431
432 HANDLE hDone = NULL;
433
CreateFileJob()434 void CreateFileJob() {
435 HANDLE hFile = CreateFileA("ZZZ\\tmpfile", GENERIC_READ | GENERIC_WRITE,
436 FILE_SHARE_READ, NULL, CREATE_ALWAYS,
437 FILE_ATTRIBUTE_NORMAL, NULL);
438 CloseHandle(hFile);
439 DWORD attr1 = GetFileAttributes("ZZZ"); // "Concurrent write" is here.
440 }
441
PrintDirectoryListingJob(void * param)442 DWORD CALLBACK PrintDirectoryListingJob(void *param) {
443 Sleep(500);
444 WIN32_FIND_DATAA data;
445
446 // "Current write" is here.
447 HANDLE hFind = FindFirstFileA("ZZZ/*", &data);
448 CHECK(hFind != INVALID_HANDLE_VALUE);
449
450 CloseHandle(hFind);
451 SetEvent(hDone);
452 return 0;
453 }
454
455 // This test is not very friendly to bots environment, so you should only
456 // run it manually.
TEST(NegativeTests,DISABLED_CreateFileVsFindFirstFileTest)457 TEST(NegativeTests, DISABLED_CreateFileVsFindFirstFileTest) {
458 hDone = ::CreateEvent(NULL, false, false, NULL);
459
460 ::CreateDirectory("ZZZ", NULL);
461
462 // Run PrintDirectoryListingJob in a concurrent thread.
463 CHECK(::QueueUserWorkItem(PrintDirectoryListingJob, NULL,
464 WT_EXECUTELONGFUNCTION));
465 CreateFileJob();
466
467 ::WaitForSingleObject(hDone, INFINITE);
468 ::CloseHandle(hDone);
469 CHECK(::DeleteFile("ZZZ\\tmpfile"));
470 CHECK(::RemoveDirectory("ZZZ"));
471 }
472
473 } //namespace
474
475 namespace WindowsAtomicsTests { // {{{1
476 // This test should not give us any reports if compiled with proper MSVS flags.
477 // The Atomic_{Read,Write} functions are ignored in racecheck_unittest.ignore
478
479 int GLOB = 42;
480
Atomic_Read(volatile const int * ptr)481 inline int Atomic_Read(volatile const int* ptr) {
482 // MSVS volatile gives us atomicity.
483 int value = *ptr;
484 return value;
485 }
486
Atomic_Write(volatile int * ptr,int value)487 inline void Atomic_Write(volatile int* ptr, int value) {
488 // MSVS volatile gives us atomicity.
489 *ptr = value;
490 }
491
Worker()492 void Worker() {
493 int value = Atomic_Read(&GLOB);
494 Atomic_Write(&GLOB, ~value);
495 }
496
TEST(NegativeTests,WindowsAtomicsTests)497 TEST(NegativeTests, WindowsAtomicsTests) {
498 MyThreadArray mta(Worker, Worker);
499 mta.Start();
500 mta.Join();
501 }
502
503 } // namespace
504
505 namespace WindowsSemaphoreTests {
Poster(int * var,HANDLE sem)506 void Poster(int *var, HANDLE sem) {
507 *var = 1;
508 ReleaseSemaphore(sem, 1, NULL);
509 }
510
Waiter(int * var,HANDLE sem)511 void Waiter(int *var, HANDLE sem) {
512 DWORD ret = ::WaitForSingleObject(sem, INFINITE);
513 ASSERT_EQ(ret, WAIT_OBJECT_0);
514 EXPECT_EQ(*var, 1);
515 }
516
TEST(NegativeTests,SimpleSemaphoreTest)517 TEST(NegativeTests, SimpleSemaphoreTest) {
518 HANDLE sem = CreateSemaphore(NULL,
519 0 /* initial count */,
520 20 /* max count */,
521 NULL);
522 ASSERT_TRUE(sem != NULL);
523
524 {
525 int VAR = 0;
526 ThreadPool tp(2);
527 tp.StartWorkers();
528 tp.Add(NewCallback(Waiter, &VAR, sem));
529 tp.Add(NewCallback(Poster, &VAR, sem));
530 }
531
532 CloseHandle(sem);
533 }
534
TEST(NegativeTests,DISABLED_SemaphoreNameReuseTest)535 TEST(NegativeTests, DISABLED_SemaphoreNameReuseTest) {
536 // TODO(timurrrr): Semaphore reuse is not yet understood by TSan.
537 const char NAME[] = "SemaphoreZZZ";
538 HANDLE h1 = CreateSemaphore(NULL, 0, 10, NAME),
539 h2 = CreateSemaphore(NULL, 0, 15, NAME);
540 ASSERT_TRUE(h1 != NULL);
541 ASSERT_TRUE(h2 != NULL);
542
543 // h1 and h2 refer to the same semaphore but are not equal.
544 EXPECT_NE(h1, h2);
545
546 {
547 int VAR = 0;
548 ThreadPool tp(2);
549 tp.StartWorkers();
550 tp.Add(NewCallback(Waiter, &VAR, h1));
551 tp.Add(NewCallback(Poster, &VAR, h2));
552 }
553
554 CloseHandle(h1);
555 CloseHandle(h2);
556 }
557
558 }
559
560 namespace HandleReuseTests {
561
Waker(int * var,HANDLE h)562 void Waker(int *var, HANDLE h) {
563 *var = 1;
564 SetEvent(h);
565 }
566
Waiter(int * var,HANDLE h)567 void Waiter(int *var, HANDLE h) {
568 DWORD ret = ::WaitForSingleObject(h, INFINITE);
569 ASSERT_EQ(ret, WAIT_OBJECT_0);
570 EXPECT_EQ(*var, 1);
571 }
572
TEST(NegativeTests,DISABLED_EventHandleReuseTest)573 TEST(NegativeTests, DISABLED_EventHandleReuseTest) {
574 // TODO(timurrrr): DuplicateHandle is not yet understood by TSan.
575 HANDLE h1 = CreateEvent(NULL, false, false, NULL);
576 ASSERT_TRUE(h1 != NULL);
577 HANDLE h2 = NULL;
578 DuplicateHandle(GetCurrentProcess(), h1,
579 GetCurrentProcess(), &h2,
580 0 /* access */, FALSE /* inherit*/, DUPLICATE_SAME_ACCESS);
581 ASSERT_TRUE(h2 != NULL);
582
583 // h1 and h2 refer to the same Event but are not equal.
584 EXPECT_NE(h1, h2);
585
586 {
587 int VAR = 0;
588 ThreadPool tp(2);
589 tp.StartWorkers();
590 tp.Add(NewCallback(Waiter, &VAR, h1));
591 tp.Add(NewCallback(Waker, &VAR, h2));
592 }
593
594 CloseHandle(h1);
595 CloseHandle(h2);
596 }
597
598 }
599 // End {{{1
600 // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
601