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
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
9 #import <Foundation/Foundation.h>
11 invisible_barrier_t barrier2;
24 @interface TestDeallocObject : NSObject {
33 @implementation TestDeallocObject
41 - (void)accessMember {
50 @interface TestCXXDestructObject : NSObject {
52 NeedCleanup cxxMemberWithCleanup;
57 @implementation TestCXXDestructObject
58 - (void)accessMember {
59 int local = cxxMemberWithCleanup.x;
64 @interface TestInitializeObject : NSObject
67 @implementation TestInitializeObject
68 static long InitializerAccessedGlobal = 0;
70 InitializerAccessedGlobal = 42;
74 int 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);
82 TestDeallocObject *tdo = [[TestDeallocObject alloc] init];
83 TestCXXDestructObject *tcxxdo = [[TestCXXDestructObject alloc] init];
85 [tcxxdo accessMember];
87 dispatch_queue_t q = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
89 [TestInitializeObject new];
90 barrier_wait(&barrier);
91 long local = InitializerAccessedGlobal;
94 [tcxxdo accessMember];
95 barrier_wait(&barrier2);
98 barrier_wait(&barrier);
99 [TestInitializeObject new];
100 long local = InitializerAccessedGlobal;
103 [tcxxdo accessMember];
104 barrier_wait(&barrier2);
107 barrier_wait(&barrier2);
113 // CHECK-NOT: ThreadSanitizer: data race