[tsan] Test that false races from ObjC's dealloc, .cxx_destruct, and initialize are...
authorAnna Zaks <ganna@apple.com>
Sat, 12 Nov 2016 00:46:07 +0000 (00:46 +0000)
committerAnna Zaks <ganna@apple.com>
Sat, 12 Nov 2016 00:46:07 +0000 (00:46 +0000)
Differential Revision: https://reviews.llvm.org/D26228

llvm-svn: 286693

compiler-rt/test/tsan/Darwin/norace-objcxx-run-time.mm [new file with mode: 0644]

diff --git a/compiler-rt/test/tsan/Darwin/norace-objcxx-run-time.mm b/compiler-rt/test/tsan/Darwin/norace-objcxx-run-time.mm
new file mode 100644 (file)
index 0000000..0cf729e
--- /dev/null
@@ -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 <Foundation/Foundation.h>
+#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