1/* Copyright (c) 2008-2010, Google Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27// This file is a part of a test suite for ThreadSanitizer, a race detector. 28// Author: Konstantin Serebryany. 29 30// These 4 lines need to go before any include from libstdc++. 31// See include/bits/c++config in libstdc++ for details. 32#include "dynamic_annotations.h" 33#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(a) ANNOTATE_HAPPENS_BEFORE(a) 34#define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(a) ANNOTATE_HAPPENS_AFTER(a) 35#define _GLIBCXX_EXTERN_TEMPLATE -1 36 37#include <stdio.h> 38#include <pthread.h> 39#include <unistd.h> 40#include <assert.h> 41#include <memory> 42#include <string> 43 44#include "test_utils.h" 45#include <gtest/gtest.h> 46 47#if defined(__cplusplus) && defined(__GNUC__) 48#include <features.h> 49// These tests verify that no false positives are reported due to custom 50// synchronization in libstdc++. 51// As of gcc 4.6, libstdc++ has HAPPENS_BEFORE/AFTER annotations in key places. 52 53namespace LibStdCPlusPlus_basic_string_Test { // {{{1 54// If reference counting inside basic_string is not understood 55// by a race detector, a false race may be reported between 56// basic_string::some_accessor and basic_string::~basic_string 57 58string *s; 59 60pthread_mutex_t mu; 61pthread_cond_t cv; 62int done = 0; 63 64void *Thread(void*) { 65 string x = *s; // calls _M_refcopy(). 66 67 pthread_mutex_lock(&mu); 68 done++; 69 pthread_cond_signal(&cv); 70 pthread_mutex_unlock(&mu); 71 72 assert(x == "foo"); 73 // x is destructed, calls _M_dispose 74 return NULL; 75} 76 77const int kNThreads = 3; 78 79TEST(LibStdCPlusPlus, basic_string_Test) { 80 if (!__GNUC_PREREQ(4, 6)) { 81 printf("This test is likely to produce a false race report " 82 "with libstdc++ earlier than 4.6; not running\n"); 83 return; 84 } 85 86 s = new string("foo"); 87 pthread_t t[kNThreads]; 88 pthread_mutex_init(&mu, 0); 89 pthread_cond_init(&cv, 0); 90 // start threads. 91 for (int i = 0; i < kNThreads; i++) { 92 pthread_create(&t[i], 0, Thread, 0); 93 } 94 // wait for threads to copy 's', but don't wait for threads to exit. 95 pthread_mutex_lock(&mu); 96 while (done != kNThreads) 97 pthread_cond_wait(&cv, &mu); 98 pthread_mutex_unlock(&mu); 99 // s has been copied few times, now delete it. 100 // Last of the destructors (either here ot in Thread() will call _M_destroy). 101 delete s; // calls _M_dispose. 102} 103} // namespace 104 105namespace LibStdCPlusPlus_shared_ptr_Test { // {{{1 106// If reference counting inside shared_ptr is not understood 107// by a race detector, a false race may be reported between 108// Foo::Check() and Foo:~Foo(). 109class Foo { 110 public: 111 Foo() : a_(777) { } 112 ~Foo() { 113 a_ = 0xDEAD; 114 } 115 void Check() { 116 assert(a_ == 777); 117 } 118 private: 119 int a_; 120}; 121 122shared_ptr<Foo> *s; 123 124pthread_mutex_t mu; 125pthread_cond_t cv; 126int done = 0; 127 128void *Thread(void*) { 129 shared_ptr<Foo> x(*s); 130 131 pthread_mutex_lock(&mu); 132 done++; 133 pthread_cond_signal(&cv); 134 pthread_mutex_unlock(&mu); 135 136 x->Check(); 137 // x is destructed. 138 return NULL; 139} 140 141TEST(LibStdCPlusPlus, shared_ptr_Test) { 142 143 if (!__GNUC_PREREQ(4, 6)) { 144 printf("This test is likely to produce a false race report " 145 "with libstdc++ earlier than 4.6; not running\n"); 146 return; 147 } 148 const int kNThreads = 3; 149 s = new shared_ptr<Foo>(new Foo); 150 pthread_t t[kNThreads]; 151 pthread_mutex_init(&mu, 0); 152 pthread_cond_init(&cv, 0); 153 // start threads. 154 for (int i = 0; i < kNThreads; i++) { 155 pthread_create(&t[i], 0, Thread, 0); 156 } 157 // wait for threads to copy 's', but don't wait for threads to exit. 158 pthread_mutex_lock(&mu); 159 while (done != kNThreads) 160 pthread_cond_wait(&cv, &mu); 161 pthread_mutex_unlock(&mu); 162 163 delete s; 164} 165} // namespace 166 167#endif // __GNUC__ 168// End {{{1 169 // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker 170