Index: compiler-rt/trunk/test/tsan/Darwin/norace-objcxx-run-time.mm =================================================================== --- compiler-rt/trunk/test/tsan/Darwin/norace-objcxx-run-time.mm +++ compiler-rt/trunk/test/tsan/Darwin/norace-objcxx-run-time.mm @@ -0,0 +1,113 @@ +// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +// Check that we do not report races between: +// - Object retain and initialize +// - Object release and dealloc +// - Object release and .cxx_destruct + +#import +#include "../test.h" +invisible_barrier_t barrier2; + +class NeedCleanup { + public: + int x; + NeedCleanup() { + x = 1; + } + ~NeedCleanup() { + x = 0; + } +}; + +@interface TestDeallocObject : NSObject { + @public + int v; + } + - (id)init; + - (void)accessMember; + - (void)dealloc; +@end + +@implementation TestDeallocObject + - (id)init { + if ([super self]) { + v = 1; + return self; + } + return nil; + } + - (void)accessMember { + int local = v; + local++; + } + - (void)dealloc { + v = 0; + } +@end + +@interface TestCXXDestructObject : NSObject { + @public + NeedCleanup cxxMemberWithCleanup; + } + - (void)accessMember; +@end + +@implementation TestCXXDestructObject + - (void)accessMember { + int local = cxxMemberWithCleanup.x; + local++; + } +@end + +@interface TestInitializeObject : NSObject +@end + +@implementation TestInitializeObject + static long InitializerAccessedGlobal = 0; + + (void)initialize { + InitializerAccessedGlobal = 42; + } +@end + +int main(int argc, const char *argv[]) { + // Ensure that there is no race when calling initialize on TestInitializeObject; + // otherwise, the locking from ObjC runtime becomes observable. Also ensures that + // blocks are dispatched to 2 different threads. + barrier_init(&barrier, 2); + // Ensure that objects are destructed during block object release. + barrier_init(&barrier2, 3); + + TestDeallocObject *tdo = [[TestDeallocObject alloc] init]; + TestCXXDestructObject *tcxxdo = [[TestCXXDestructObject alloc] init]; + [tdo accessMember]; + [tcxxdo accessMember]; + { + dispatch_queue_t q = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + dispatch_async(q, ^{ + [TestInitializeObject new]; + barrier_wait(&barrier); + long local = InitializerAccessedGlobal; + local++; + [tdo accessMember]; + [tcxxdo accessMember]; + barrier_wait(&barrier2); + }); + dispatch_async(q, ^{ + barrier_wait(&barrier); + [TestInitializeObject new]; + long local = InitializerAccessedGlobal; + local++; + [tdo accessMember]; + [tcxxdo accessMember]; + barrier_wait(&barrier2); + }); + } + barrier_wait(&barrier2); + NSLog(@"Done."); + return 0; +} + +// CHECK: Done. +// CHECK-NOT: ThreadSanitizer: data race