zaks.anna created this revision.
zaks.anna added reviewers: kcc, kubabrecka, dvyukov.
zaks.anna added a subscriber: cfe-commits.

This introduces a function annotation that disables TSan checking for the 
function at run time. The benefit over __attribute__((no_sanitize("thread"))) 
is that the accesses within the callees will also be suppressed.

The motivation for this attribute is a guarantee given by the objective C 
language that the calls to the reference count decrement and object 
deallocation will be synchronized. To model this properly, we would need to 
intercept all ref count decrement calls (which are very common in ObjC due to 
use of ARC) and also every single message send. Instead, we propose to just 
ignore all accesses made from within dealloc at run time. The main downside is 
that this still does not introduce any synchronization, which means we might 
still report false positives if the code that relies on this synchronization is 
not executed from within dealloc. However, we have not seen this in practice so 
far and think these cases will be very rare.

(This problem is similar in nature to https://reviews.llvm.org/D21609; 
unfortunately, the same solution does not apply here.)


https://reviews.llvm.org/D25857

Files:
  lib/CodeGen/CodeGenFunction.cpp
  test/CodeGen/sanitize-thread-attr-dealloc.m


Index: test/CodeGen/sanitize-thread-attr-dealloc.m
===================================================================
--- /dev/null
+++ test/CodeGen/sanitize-thread-attr-dealloc.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck 
-check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s 
-fsanitize=thread | FileCheck -check-prefix=TSAN %s
+
+__attribute__((objc_root_class))
+@interface NSObject
+- (void)dealloc;
+@end
+
+@interface MyObject : NSObject
+- (void) dealloc;
+@end
+
+@implementation MyObject
+- (void)dealloc {
+  [super dealloc];
+}
+@end
+
+// WITHOUT-NOT: "sanitize_thread_no_checking_at_run_time"
+
+// TSAN: dealloc{{.*}}) [[ATTR:#[0-9]+]]
+// TSAN: attributes [[ATTR]] = { nounwind sanitize_thread {{.*}} 
"sanitize_thread_no_checking_at_run_time" {{.*}} }
+
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -714,6 +714,13 @@
   if (SanOpts.has(SanitizerKind::SafeStack))
     Fn->addFnAttr(llvm::Attribute::SafeStack);
 
+  // Ignore TSan memory acesses from within dealloc and all of its calees at
+  // run time.
+  if (SanOpts.has(SanitizerKind::Thread))
+    if (const auto *M = dyn_cast_or_null<ObjCMethodDecl>(D))
+      if (M->getMethodFamily() == OMF_dealloc)
+        Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
+
   // Apply xray attributes to the function (as a string, for now)
   if (D && ShouldXRayInstrumentFunction()) {
     if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {


Index: test/CodeGen/sanitize-thread-attr-dealloc.m
===================================================================
--- /dev/null
+++ test/CodeGen/sanitize-thread-attr-dealloc.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=thread | FileCheck -check-prefix=TSAN %s
+
+__attribute__((objc_root_class))
+@interface NSObject
+- (void)dealloc;
+@end
+
+@interface MyObject : NSObject
+- (void) dealloc;
+@end
+
+@implementation MyObject
+- (void)dealloc {
+  [super dealloc];
+}
+@end
+
+// WITHOUT-NOT: "sanitize_thread_no_checking_at_run_time"
+
+// TSAN: dealloc{{.*}}) [[ATTR:#[0-9]+]]
+// TSAN: attributes [[ATTR]] = { nounwind sanitize_thread {{.*}} "sanitize_thread_no_checking_at_run_time" {{.*}} }
+
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -714,6 +714,13 @@
   if (SanOpts.has(SanitizerKind::SafeStack))
     Fn->addFnAttr(llvm::Attribute::SafeStack);
 
+  // Ignore TSan memory acesses from within dealloc and all of its calees at
+  // run time.
+  if (SanOpts.has(SanitizerKind::Thread))
+    if (const auto *M = dyn_cast_or_null<ObjCMethodDecl>(D))
+      if (M->getMethodFamily() == OMF_dealloc)
+        Fn->addFnAttr("sanitize_thread_no_checking_at_run_time");
+
   // Apply xray attributes to the function (as a string, for now)
   if (D && ShouldXRayInstrumentFunction()) {
     if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to