1// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation 2// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s 3 4// Check that we do not report races between: 5// - Object retain and initialize 6// - Object release and dealloc 7// - Object release and .cxx_destruct 8 9#import <Foundation/Foundation.h> 10#include "../test.h" 11invisible_barrier_t barrier2; 12 13class NeedCleanup { 14 public: 15 int x; 16 NeedCleanup() { 17 x = 1; 18 } 19 ~NeedCleanup() { 20 x = 0; 21 } 22}; 23 24@interface TestDeallocObject : NSObject { 25 @public 26 int v; 27 } 28 - (id)init; 29 - (void)accessMember; 30 - (void)dealloc; 31@end 32 33@implementation TestDeallocObject 34 - (id)init { 35 if ([super self]) { 36 v = 1; 37 return self; 38 } 39 return nil; 40 } 41 - (void)accessMember { 42 int local = v; 43 local++; 44 } 45 - (void)dealloc { 46 v = 0; 47 } 48@end 49 50@interface TestCXXDestructObject : NSObject { 51 @public 52 NeedCleanup cxxMemberWithCleanup; 53 } 54 - (void)accessMember; 55@end 56 57@implementation TestCXXDestructObject 58 - (void)accessMember { 59 int local = cxxMemberWithCleanup.x; 60 local++; 61 } 62@end 63 64@interface TestInitializeObject : NSObject 65@end 66 67@implementation TestInitializeObject 68 static long InitializerAccessedGlobal = 0; 69 + (void)initialize { 70 InitializerAccessedGlobal = 42; 71 } 72@end 73 74int main(int argc, const char *argv[]) { 75 // Ensure that there is no race when calling initialize on TestInitializeObject; 76 // otherwise, the locking from ObjC runtime becomes observable. Also ensures that 77 // blocks are dispatched to 2 different threads. 78 barrier_init(&barrier, 2); 79 // Ensure that objects are destructed during block object release. 80 barrier_init(&barrier2, 3); 81 82 TestDeallocObject *tdo = [[TestDeallocObject alloc] init]; 83 TestCXXDestructObject *tcxxdo = [[TestCXXDestructObject alloc] init]; 84 [tdo accessMember]; 85 [tcxxdo accessMember]; 86 { 87 dispatch_queue_t q = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); 88 dispatch_async(q, ^{ 89 [TestInitializeObject new]; 90 barrier_wait(&barrier); 91 long local = InitializerAccessedGlobal; 92 local++; 93 [tdo accessMember]; 94 [tcxxdo accessMember]; 95 barrier_wait(&barrier2); 96 }); 97 dispatch_async(q, ^{ 98 barrier_wait(&barrier); 99 [TestInitializeObject new]; 100 long local = InitializerAccessedGlobal; 101 local++; 102 [tdo accessMember]; 103 [tcxxdo accessMember]; 104 barrier_wait(&barrier2); 105 }); 106 } 107 barrier_wait(&barrier2); 108 NSLog(@"Done."); 109 return 0; 110} 111 112// CHECK: Done. 113// CHECK-NOT: ThreadSanitizer: data race 114