Index: compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc
===================================================================
--- compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc
+++ compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc
@@ -318,17 +318,27 @@
   return (uptr)obj;
 }
 
+// Defined in <objc-sync.h>
+#define OBJC_SYNC_SUCCESS 0
+
 TSAN_INTERCEPTOR(int, objc_sync_enter, void *obj) {
   SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj);
-  int result = REAL(objc_sync_enter)(obj);
-  if (obj) Acquire(thr, pc, SyncAddressForObjCObject(obj));
+  if (!obj) return REAL(objc_sync_enter)(obj);
+  uptr addr = SyncAddressForObjCObject(obj);
+  MutexPreLock(thr, pc, addr);
+  int result = REAL(objc_sync_enter)(obj); // Always returns OBJC_SYNC_SUCCESS
+  MutexPostLock(thr, pc, addr);
   return result;
 }
 
 TSAN_INTERCEPTOR(int, objc_sync_exit, void *obj) {
   SCOPED_TSAN_INTERCEPTOR(objc_sync_exit, obj);
-  if (obj) Release(thr, pc, SyncAddressForObjCObject(obj));
-  return REAL(objc_sync_exit)(obj);
+  if (!obj) return REAL(objc_sync_exit)(obj);
+  uptr addr = SyncAddressForObjCObject(obj);
+  MutexUnlock(thr, pc, addr);
+  int result = REAL(objc_sync_exit)(obj);
+  if (result != OBJC_SYNC_SUCCESS) MutexInvalidAccess(thr, pc, addr);
+  return result;
 }
 
 // On macOS, libc++ is always linked dynamically, so intercepting works the
Index: compiler-rt/test/tsan/Darwin/objc-synchronize-cycle.mm
===================================================================
--- /dev/null
+++ compiler-rt/test/tsan/Darwin/objc-synchronize-cycle.mm
@@ -0,0 +1,31 @@
+// RUN: %clangxx_tsan %s -o %t -framework Foundation -fobjc-arc %darwin_min_target_with_full_runtime_arc_support
+// RUN:                                   not %run %t 2>&1 | FileCheck %s
+// RUN: %env_tsan_opts=detect_deadlocks=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_tsan_opts=detect_deadlocks=0     %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED
+
+#import <Foundation/Foundation.h>
+
+int main() {
+  @autoreleasepool {
+    NSObject* obj1 = [NSObject new];
+    NSObject* obj2 = [NSObject new];
+
+    // obj1 -> obj2
+    @synchronized(obj1) {
+      @synchronized(obj2) {
+      }
+    }
+
+    // obj1 -> obj1
+    @synchronized(obj2) {
+      @synchronized(obj1) {
+// CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+      }
+    }
+  }
+
+  NSLog(@"PASS");
+// DISABLED-NOT: ThreadSanitizer
+// DISABLED: PASS
+  return 0;
+}