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
36void DummyWorker() {
37}
38
39void LongWorker() {
40  Sleep(1);
41  volatile int i = 1 << 20;
42  while(i--);
43}
44
45void WriteWorker(int *var) {
46  LongWorker();
47  *var = 42;
48}
49
50void VeryLongWriteWorker(int *var) {
51  Sleep(1000);
52  *var = 42;
53}
54
55TEST(NegativeTests, WindowsCreateThreadFailureTest) {  // {{{1
56  HANDLE t = ::CreateThread(0, -1,
57                           (LPTHREAD_START_ROUTINE)DummyWorker, 0, 0, 0);
58  CHECK(t == 0);
59}
60
61TEST(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
77TEST(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
89TEST(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
98TEST(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
113TEST(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
128TEST(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
149TEST(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
171namespace RegisterWaitForSingleObjectTest {  // {{{1
172StealthNotification *n = NULL;
173HANDLE monitored_object = NULL;
174
175void SignalStealthNotification() {
176  n->wait();
177  SetEvent(monitored_object);
178}
179
180void foo() { }
181
182void 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
188TEST(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
226namespace QueueUserWorkItemTests {
227DWORD CALLBACK Callback(void *param) {
228  int *ptr = (int*)param;
229  (*ptr)++;
230  delete ptr;
231  return 0;
232}
233
234TEST(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
246int GLOB = 42;
247
248DWORD CALLBACK Callback2(void *param) {
249  StealthNotification *ptr = (StealthNotification*)param;
250  GLOB++;
251  Sleep(100);
252  ptr->signal();
253  return 0;
254}
255
256TEST(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
270namespace WindowsCriticalSectionTest {  // {{{1
271CRITICAL_SECTION cs;
272
273TEST(NegativeTests, WindowsCriticalSectionTest) {
274  InitializeCriticalSection(&cs);
275  EnterCriticalSection(&cs);
276  TryEnterCriticalSection(&cs);
277  LeaveCriticalSection(&cs);
278  DeleteCriticalSection(&cs);
279}
280}  // namespace
281
282
283namespace WindowsSRWLockTest {  // {{{1
284#if WINVER >= 0x0600 // Vista or Windows Server 2000
285SRWLOCK SRWLock;
286int *obj;
287
288void Reader() {
289  AcquireSRWLockShared(&SRWLock);
290  CHECK(*obj <= 2 && *obj >= 0);
291  ReleaseSRWLockShared(&SRWLock);
292}
293
294void Writer() {
295  AcquireSRWLockExclusive(&SRWLock);
296  (*obj)++;
297  ReleaseSRWLockExclusive(&SRWLock);
298}
299
300#if 0  // This doesn't work in older versions of Windows.
301void TryReader() {
302  if (TryAcquireSRWLockShared(&SRWLock)) {
303    CHECK(*obj <= 2 && *obj >= 0);
304    ReleaseSRWLockShared(&SRWLock);
305  }
306}
307
308void TryWriter() {
309  if (TryAcquireSRWLockExclusive(&SRWLock)) {
310    (*obj)++;
311    ReleaseSRWLockExclusive(&SRWLock);
312  }
313}
314#endif
315
316TEST(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
329TEST(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
346namespace WindowsConditionVariableSRWTest {  // {{{1
347#if WINVER >= 0x0600 // Vista or Windows Server 2000
348SRWLOCK SRWLock;
349CONDITION_VARIABLE cv;
350bool cond;
351int *obj;
352
353StealthNotification n;
354
355void WaiterSRW() {
356  *obj = 1;
357  n.wait();
358  AcquireSRWLockExclusive(&SRWLock);
359  cond = true;
360  WakeConditionVariable(&cv);
361  ReleaseSRWLockExclusive(&SRWLock);
362}
363
364void 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
375TEST(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
391namespace WindowsInterlockedListTest {  // {{{1
392SLIST_HEADER list;
393
394struct Item {
395  SLIST_ENTRY entry;
396  int foo;
397};
398
399void Push() {
400  Item *item = new Item;
401  item->foo = 42;
402  InterlockedPushEntrySList(&list, (PSINGLE_LIST_ENTRY)item);
403}
404
405void 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
414TEST(NegativeTests, WindowsInterlockedListTest) {
415  InitializeSListHead(&list);
416  MyThreadArray t(Push, Pop);
417  t.Start();
418  t.Join();
419}
420
421}  // namespace
422
423namespace 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
432HANDLE hDone = NULL;
433
434void 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
442DWORD 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.
457TEST(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
475namespace 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
479int GLOB = 42;
480
481inline int Atomic_Read(volatile const int* ptr) {
482  // MSVS volatile gives us atomicity.
483  int value = *ptr;
484  return value;
485}
486
487inline void Atomic_Write(volatile int* ptr, int value) {
488  // MSVS volatile gives us atomicity.
489  *ptr = value;
490}
491
492void Worker() {
493  int value = Atomic_Read(&GLOB);
494  Atomic_Write(&GLOB, ~value);
495}
496
497TEST(NegativeTests, WindowsAtomicsTests) {
498  MyThreadArray mta(Worker, Worker);
499  mta.Start();
500  mta.Join();
501}
502
503}  // namespace
504
505namespace WindowsSemaphoreTests {
506void Poster(int *var, HANDLE sem) {
507  *var = 1;
508  ReleaseSemaphore(sem, 1, NULL);
509}
510
511void 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
517TEST(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
535TEST(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
560namespace HandleReuseTests {
561
562void Waker(int *var, HANDLE h) {
563  *var = 1;
564  SetEvent(h);
565}
566
567void 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
573TEST(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