@@ -211,6 +211,10 @@ struct ThreadSanitizer {
211
211
FunctionCallee TsanVptrUpdate;
212
212
FunctionCallee TsanVptrLoad;
213
213
FunctionCallee MemmoveFn, MemcpyFn, MemsetFn;
214
+
215
+ // Instrinsics for disabling/enabling instrumentation
216
+ // for specific code section
217
+ FunctionCallee TsanDisableFn, TsanEnableFn;
214
218
};
215
219
216
220
void insertModuleCtor (Module &M) {
@@ -414,6 +418,12 @@ void ThreadSanitizer::initialize(Module &M, const TargetLibraryInfo &TLI) {
414
418
" __tsan_memset" ,
415
419
TLI.getAttrList (&Ctx, {1 }, /* Signed=*/ true , /* Ret=*/ false , Attr),
416
420
IRB.getPtrTy (), IRB.getPtrTy (), IRB.getInt32Ty (), IntptrTy);
421
+
422
+ // ///////////////////////////////////////////////////////////////////////////
423
+ // This code is for disabling/enabling instrumentation
424
+ // for specific code section
425
+ TsanEnableFn = M.getOrInsertFunction (" __tsan_enable" , Attr, IRB.getVoidTy ());
426
+ TsanDisableFn = M.getOrInsertFunction (" __tsan_disable" , Attr, IRB.getVoidTy ());
417
427
}
418
428
419
429
static bool isVtableAccess (Instruction *I) {
@@ -649,11 +659,42 @@ bool ThreadSanitizer::sanitizeFunction(
649
659
bool SanitizeFunction = F.hasFnAttribute (Attribute::SanitizeThread);
650
660
const DataLayout &DL = F.getParent ()->getDataLayout ();
651
661
662
+ // /////////////////////////////////////////////////////////////////////////////
663
+ // List of instructions (function calls) to delete
664
+ SmallVector<CallInst*, 8 > EnableDisableFuncToDelete;
665
+
666
+ // Counter for considering nesting __tsan_disable/__tsan_enable
667
+ int disableEnableNesting = 0 ;
668
+
652
669
// Traverse all instructions, collect loads/stores/returns, check for calls.
653
670
for (auto &BB : F) {
654
671
LLVM_DEBUG (dbgs () << " \n Instrumenting BB: " << BB.getName () << " \n " );
655
672
for (auto &Inst : BB) {
656
673
LLVM_DEBUG (dbgs () << " Instrumenting I: " << Inst << " \n " );
674
+ // /////////////////////////////////////////////////////////////////////////////
675
+ // This code is for disabling/enabling instrumentation
676
+ // for specific code section
677
+ //
678
+ // Check whether we encountered TSan disable/enable intrinsics
679
+ if (auto *CI = dyn_cast<CallInst>(&Inst)) {
680
+ Function *CalledFunc = CI->getCalledFunction ();
681
+ if (CalledFunc) {
682
+ // errs() << "CalledFunc: " << CalledFunc->getName() << "\n";
683
+ if (CalledFunc->getName () == " __tsan_disable" ) {
684
+ disableEnableNesting++;
685
+ EnableDisableFuncToDelete.push_back (CI);
686
+ continue ;
687
+ } else if (CalledFunc->getName () == " __tsan_enable" ) {
688
+ disableEnableNesting--;
689
+ EnableDisableFuncToDelete.push_back (CI);
690
+ continue ;
691
+ }
692
+ }
693
+ }
694
+
695
+ if (disableEnableNesting > 0 )
696
+ continue ;
697
+ // /////////////////////////////////////////////////////////////////////////////
657
698
658
699
// Skip instructions inserted by another instrumentation.
659
700
if (Inst.hasMetadata (LLVMContext::MD_nosanitize))
@@ -688,6 +729,22 @@ bool ThreadSanitizer::sanitizeFunction(
688
729
EAI, EAIGlobal);
689
730
}
690
731
732
+ // ////////////////////////////////////////////////////////////////////////////
733
+ // This is for disabling/enabling TSan instrumentation
734
+ // Disable for now check of matching
735
+ /*
736
+ if (disableEnableNesting != 0) {
737
+ // Error: __tsan_enable without __tsan_disable
738
+ report_fatal_error("Unmatched __tsan_enable__ call in function " +
739
+ F.getName());
740
+ }
741
+ */
742
+
743
+ // Erase all __tsan_disable/enable functions
744
+ for (auto *CI: EnableDisableFuncToDelete)
745
+ CI->eraseFromParent ();
746
+ // ////////////////////////////////////////////////////////////////////////////
747
+
691
748
// We have collected all loads and stores.
692
749
// FIXME: many of these accesses do not need to be checked for races
693
750
// (e.g. variables that do not escape, etc).
0 commit comments