Skip to content

Commit

Permalink
[tsan] Add interceptors for objc_sync_enter and objc_sync_exit
Browse files Browse the repository at this point in the history
Objective-C's @synchronize synchronization primitive uses calls to objc_sync_enter and objc_sync_exit runtime functions. In most cases, they end up just calling pthread_mutex_lock/pthread_mutex_unlock, but there are some cases where the synchronization from pthread_mutex_lock/pthread_mutex_unlock interceptors isn't enough. Let's add explicit interceptors for objc_sync_enter and objc_sync_exit to handle all cases.

Differential Revision: https://reviews.llvm.org/D45487

llvm-svn: 329982
  • Loading branch information
kubamracek committed Apr 13, 2018
1 parent 223f4c7 commit 296ce3b
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
2 changes: 1 addition & 1 deletion compiler-rt/lib/tsan/CMakeLists.txt
Expand Up @@ -118,7 +118,7 @@ if(APPLE)
RTUbsan
CFLAGS ${TSAN_RTL_CFLAGS}
LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
LINK_LIBS ${TSAN_LINK_LIBS}
LINK_LIBS ${TSAN_LINK_LIBS} objc
PARENT_TARGET tsan)
add_compiler_rt_object_libraries(RTTsan_dynamic
OS ${TSAN_SUPPORTED_OS}
Expand Down
13 changes: 13 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cc
Expand Up @@ -294,6 +294,19 @@ TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) {

#endif // #if defined(__has_include) && __has_include(<xpc/xpc.h>)

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, (uptr)obj);
return result;
}

TSAN_INTERCEPTOR(int, objc_sync_exit, void *obj) {
SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj);
if (obj) Release(thr, pc, (uptr)obj);
return REAL(objc_sync_exit)(obj);
}

// On macOS, libc++ is always linked dynamically, so intercepting works the
// usual way.
#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
Expand Down
57 changes: 57 additions & 0 deletions compiler-rt/test/tsan/Darwin/objc-synchronize.mm
@@ -0,0 +1,57 @@
// RUN: %clangxx_tsan %s -o %t -framework Foundation -fobjc-arc %darwin_min_target_with_full_runtime_arc_support
// RUN: %run %t 2>&1 | FileCheck %s

#import <Foundation/Foundation.h>

@interface MyClass : NSObject {
long field;
}
@property (nonatomic, readonly) long value;
@end

dispatch_group_t group;

@implementation MyClass

- (void) start {
dispatch_queue_t q = dispatch_queue_create(NULL, NULL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < 1000; i++) {
dispatch_async(q, ^{
@synchronized(self) {
self->field = i;
}
});
}
});
}

- (long) value {
@synchronized(self) {
return self->field;
}
}

- (void)dealloc {
dispatch_group_leave(group);
}

@end

int main() {
group = dispatch_group_create();
@autoreleasepool {
for (int j = 0; j < 100; ++j) {
dispatch_group_enter(group);
MyClass *obj = [[MyClass alloc] init];
[obj start];
long x = obj.value;
(void)x;
}
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"Hello world");
}

// CHECK: Hello world
// CHECK-NOT: WARNING: ThreadSanitizer

0 comments on commit 296ce3b

Please sign in to comment.