[tsan] treat vtable pointer updates in a special way (requires tbaa); fix a bug ...
authorKostya Serebryany <kcc@google.com>
Mon, 26 Mar 2012 17:35:03 +0000 (17:35 +0000)
committerKostya Serebryany <kcc@google.com>
Mon, 26 Mar 2012 17:35:03 +0000 (17:35 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@153448 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Instrumentation/ThreadSanitizer.cpp
test/Instrumentation/ThreadSanitizer/lit.local.cfg [new file with mode: 0644]
test/Instrumentation/ThreadSanitizer/vptr_update.ll [new file with mode: 0644]

index 85fda30499f1c1de2036fd56174d905e57ffa0d6..b774211a8541f8348299db48399998681578eed0 100644 (file)
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Intrinsics.h"
 #include "llvm/Function.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Metadata.h"
 #include "llvm/Module.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/IRBuilder.h"
 #include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Transforms/Instrumentation.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -61,6 +64,7 @@ struct ThreadSanitizer : public FunctionPass {
   static const size_t kNumberOfAccessSizes = 5;
   Value *TsanRead[kNumberOfAccessSizes];
   Value *TsanWrite[kNumberOfAccessSizes];
+  Value *TsanVptrUpdate;
 };
 }  // namespace
 
@@ -105,6 +109,9 @@ bool ThreadSanitizer::doInitialization(Module &M) {
     TsanWrite[i] = M.getOrInsertFunction(WriteName, IRB.getVoidTy(),
                                          IRB.getInt8PtrTy(), NULL);
   }
+  TsanVptrUpdate = M.getOrInsertFunction("__tsan_vptr_update", IRB.getVoidTy(),
+                                         IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
+                                         NULL);
   return true;
 }
 
@@ -151,10 +158,21 @@ bool ThreadSanitizer::runOnFunction(Function &F) {
       IRBuilder<> IRBRet(RetVec[i]);
       IRBRet.CreateCall(TsanFuncExit);
     }
+    Res = true;
   }
   return Res;
 }
 
+static bool isVtableAccess(Instruction *I) {
+  if (MDNode *Tag = I->getMetadata(LLVMContext::MD_tbaa)) {
+    if (Tag->getNumOperands() < 1) return false;
+    if (MDString *Tag1 = dyn_cast<MDString>(Tag->getOperand(0))) {
+      if (Tag1->getString() == "vtable pointer") return true;
+    }
+  }
+  return false;
+}
+
 bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I) {
   IRBuilder<> IRB(I);
   bool IsWrite = isa<StoreInst>(*I);
@@ -170,6 +188,13 @@ bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I) {
     // Ignore all unusual sizes.
     return false;
   }
+  if (IsWrite && isVtableAccess(I)) {
+    Value *StoredValue = cast<StoreInst>(I)->getValueOperand();
+    IRB.CreateCall2(TsanVptrUpdate,
+                    IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()),
+                    IRB.CreatePointerCast(StoredValue, IRB.getInt8PtrTy()));
+    return true;
+  }
   size_t Idx = CountTrailingZeros_32(TypeSize / 8);
   assert(Idx < kNumberOfAccessSizes);
   Value *OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx];
diff --git a/test/Instrumentation/ThreadSanitizer/lit.local.cfg b/test/Instrumentation/ThreadSanitizer/lit.local.cfg
new file mode 100644 (file)
index 0000000..19eebc0
--- /dev/null
@@ -0,0 +1 @@
+config.suffixes = ['.ll', '.c', '.cpp']
diff --git a/test/Instrumentation/ThreadSanitizer/vptr_update.ll b/test/Instrumentation/ThreadSanitizer/vptr_update.ll
new file mode 100644 (file)
index 0000000..f318659
--- /dev/null
@@ -0,0 +1,13 @@
+; RUN: opt < %s -tsan -S | FileCheck %s
+; Check that vtable pointer updates are treated in a special way.
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define void @Foo(i8** nocapture %a, i8* %b) nounwind uwtable {
+entry:
+; CHECK: call void @__tsan_vptr_update
+  store i8* %b, i8** %a, align 8, !tbaa !0
+  ret void
+}
+!0 = metadata !{metadata !"vtable pointer", metadata !1}
+!1 = metadata !{metadata !"Simple C/C++ TBAA", null}
+