Home | History | Annotate | Download | only in unittest
      1 /*
      2   This file is part of Valgrind, a dynamic binary instrumentation
      3   framework.
      4 
      5   Copyright (C) 2008-2008 Google Inc
      6      opensource (at) 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 (at) 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 
     36 void DummyWorker() {
     37 }
     38 
     39 void LongWorker() {
     40   Sleep(1);
     41   volatile int i = 1 << 20;
     42   while(i--);
     43 }
     44 
     45 void WriteWorker(int *var) {
     46   LongWorker();
     47   *var = 42;
     48 }
     49 
     50 void VeryLongWriteWorker(int *var) {
     51   Sleep(1000);
     52   *var = 42;
     53 }
     54 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    175 void SignalStealthNotification() {
    176   n->wait();
    177   SetEvent(monitored_object);
    178 }
    179 
    180 void foo() { }
    181 
    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 
    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 {
    227 DWORD CALLBACK Callback(void *param) {
    228   int *ptr = (int*)param;
    229   (*ptr)++;
    230   delete ptr;
    231   return 0;
    232 }
    233 
    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 
    248 DWORD CALLBACK Callback2(void *param) {
    249   StealthNotification *ptr = (StealthNotification*)param;
    250   GLOB++;
    251   Sleep(100);
    252   ptr->signal();
    253   return 0;
    254 }
    255 
    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 
    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 
    288 void Reader() {
    289   AcquireSRWLockShared(&SRWLock);
    290   CHECK(*obj <= 2 && *obj >= 0);
    291   ReleaseSRWLockShared(&SRWLock);
    292 }
    293 
    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 
    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 
    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 
    355 void WaiterSRW() {
    356   *obj = 1;
    357   n.wait();
    358   AcquireSRWLockExclusive(&SRWLock);
    359   cond = true;
    360   WakeConditionVariable(&cv);
    361   ReleaseSRWLockExclusive(&SRWLock);
    362 }
    363 
    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 
    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 
    399 void Push() {
    400   Item *item = new Item;
    401   item->foo = 42;
    402   InterlockedPushEntrySList(&list, (PSINGLE_LIST_ENTRY)item);
    403 }
    404 
    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 
    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 
    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 
    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.
    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 
    481 inline int Atomic_Read(volatile const int* ptr) {
    482   // MSVS volatile gives us atomicity.
    483   int value = *ptr;
    484   return value;
    485 }
    486 
    487 inline void Atomic_Write(volatile int* ptr, int value) {
    488   // MSVS volatile gives us atomicity.
    489   *ptr = value;
    490 }
    491 
    492 void Worker() {
    493   int value = Atomic_Read(&GLOB);
    494   Atomic_Write(&GLOB, ~value);
    495 }
    496 
    497 TEST(NegativeTests, WindowsAtomicsTests) {
    498   MyThreadArray mta(Worker, Worker);
    499   mta.Start();
    500   mta.Join();
    501 }
    502 
    503 }  // namespace
    504 
    505 namespace WindowsSemaphoreTests {
    506 void Poster(int *var, HANDLE sem) {
    507   *var = 1;
    508   ReleaseSemaphore(sem, 1, NULL);
    509 }
    510 
    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 
    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 
    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 
    562 void Waker(int *var, HANDLE h) {
    563   *var = 1;
    564   SetEvent(h);
    565 }
    566 
    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 
    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