Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 28c54ab

Browse files
committed
[tsan] Do not instrument reads/writes to instruction profile counters.
We have known races on profile counters, which can be reproduced by enabling -fsanitize=thread and -fprofile-instr-generate simultaneously on a multi-threaded program. This patch avoids reporting those races by not instrumenting the reads and writes coming from the instruction profiler. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@264805 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 807b212 commit 28c54ab

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

lib/Transforms/Instrumentation/ThreadSanitizer.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/IR/Metadata.h"
3737
#include "llvm/IR/Module.h"
3838
#include "llvm/IR/Type.h"
39+
#include "llvm/ProfileData/InstrProf.h"
3940
#include "llvm/Support/CommandLine.h"
4041
#include "llvm/Support/Debug.h"
4142
#include "llvm/Support/MathExtras.h"
@@ -243,6 +244,24 @@ static bool isVtableAccess(Instruction *I) {
243244
return false;
244245
}
245246

247+
// Do not instrument known races/"benign races" that come from compiler
248+
// instrumentatin. The user has no way of suppressing them.
249+
bool shouldInstrumentReadWriteFromAddress(Value *Addr) {
250+
// Peel off GEPs and BitCasts.
251+
Addr = Addr->stripInBoundsOffsets();
252+
253+
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
254+
if (GV->hasSection()) {
255+
StringRef SectionName = GV->getSection();
256+
// Check if the global is in the PGO counters section.
257+
if (SectionName.endswith(getInstrProfCountersSectionName(
258+
/*AddSegment=*/false)))
259+
return false;
260+
}
261+
}
262+
return true;
263+
}
264+
246265
bool ThreadSanitizer::addrPointsToConstantData(Value *Addr) {
247266
// If this is a GEP, just analyze its pointer operand.
248267
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Addr))
@@ -285,10 +304,15 @@ void ThreadSanitizer::chooseInstructionsToInstrument(
285304
E = Local.rend(); It != E; ++It) {
286305
Instruction *I = *It;
287306
if (StoreInst *Store = dyn_cast<StoreInst>(I)) {
288-
WriteTargets.insert(Store->getPointerOperand());
307+
Value *Addr = Store->getPointerOperand();
308+
if (!shouldInstrumentReadWriteFromAddress(Addr))
309+
continue;
310+
WriteTargets.insert(Addr);
289311
} else {
290312
LoadInst *Load = cast<LoadInst>(I);
291313
Value *Addr = Load->getPointerOperand();
314+
if (!shouldInstrumentReadWriteFromAddress(Addr))
315+
continue;
292316
if (WriteTargets.count(Addr)) {
293317
// We will write to this temp, so no reason to analyze the read.
294318
NumOmittedReadsBeforeWrite++;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
; This test checks that we are not instrumenting unwanted acesses to globals:
2+
; - Instruction profiler counter instrumentation has known intended races.
3+
;
4+
; RUN: opt < %s -tsan -S | FileCheck %s
5+
6+
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
7+
target triple = "x86_64-apple-macosx10.9"
8+
9+
@__profc_test_gep = private global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
10+
@__profc_test_bitcast = private global [2 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
11+
@__profc_test_bitcast_foo = private global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
12+
13+
define i32 @test_gep() sanitize_thread {
14+
entry:
15+
%pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test_gep, i64 0, i64 0)
16+
%0 = add i64 %pgocount, 1
17+
store i64 %0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test_gep, i64 0, i64 0)
18+
ret i32 1
19+
}
20+
21+
define i32 @test_bitcast() sanitize_thread {
22+
entry:
23+
%0 = load <2 x i64>, <2 x i64>* bitcast ([2 x i64]* @__profc_test_bitcast to <2 x i64>*), align 8
24+
%.promoted5 = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test_bitcast_foo, i64 0, i64 0), align 8
25+
%1 = add i64 %.promoted5, 10
26+
%2 = add <2 x i64> %0, <i64 1, i64 10>
27+
store <2 x i64> %2, <2 x i64>* bitcast ([2 x i64]* @__profc_test_bitcast to <2 x i64>*), align 8
28+
store i64 %1, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test_bitcast_foo, i64 0, i64 0), align 8
29+
ret i32 undef
30+
}
31+
32+
; CHECK-NOT: {{call void @__tsan_write}}
33+
; CHECK: __tsan_init

0 commit comments

Comments
 (0)