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