Closed GoogleCodeExporter closed 9 years ago
Hi,
Thanks for the report!
What compilation options/optimization level do you use?
Original comment by dvyu...@google.com
on 19 Nov 2013 at 3:16
If I understand the situation correctly, here is what's going on:
% cat if.cc
int x;
int foo(int cond) {
if (cond)
return x;
return 0;
}
% clang -O1 if.cc -S -o - -emit-llvm
; Function Attrs: nounwind readonly uwtable
define i32 @_Z3fooi(i32 %cond) #0 {
entry:
%tobool = icmp eq i32 %cond, 0
%0 = load i32* @x, align 4, !tbaa !1
%retval.0 = select i1 %tobool, i32 0, i32 %0
ret i32 %retval.0
}
LLVM at O1 and higher hoists a safe load (from a global) out of the conditional
basic block.
This optimization is clearly hostile to tsan.
Original comment by konstant...@gmail.com
on 19 Nov 2013 at 4:34
Kostya, you are in much better position to resolve this. Can we disable that
optimization under tsan?
Original comment by dvyu...@google.com
on 19 Nov 2013 at 5:00
Sure, that's what we are going to do.
choller@, fixing this properly may take some time (there is a ongoing
discussion at LLVM about better ways to do similar stuff:
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20131118/195757.html
)
In the meantime, can you try __attribute__((no_sanitize_thread)) on that
function?
Original comment by konstant...@gmail.com
on 19 Nov 2013 at 5:10
Just FTR, here is a full reproducer with a false positive:
% cat if-race.cc
#include <pthread.h>
#include <unistd.h>
int g;
int foo(int cond) {
if (cond)
return g;
return 0;
}
void *Thread1(void *p) {
long res = foo((long)p);
sleep(1);
return (void*) res;
}
int main() {
pthread_t t;
pthread_create(&t, 0, Thread1, 0);
g = 1;
pthread_join(t, 0);
}
% clang -fsanitize=thread if-race.cc && ./a.out
% clang -fsanitize=thread if-race.cc -O1 && ./a.out
==================
WARNING: ThreadSanitizer: data race (pid=24069)
Read of size 4 at 0x7f834514ada8 by thread T1:
#0 foo(int) ??:0 (exe+0x0000000867de)
#1 Thread1(void*) ??:0 (exe+0x000000086814)
Original comment by konstant...@gmail.com
on 19 Nov 2013 at 5:43
One possible fix (will send it for review a bit later):
Index: lib/Analysis/ValueTracking.cpp
===================================================================
--- lib/Analysis/ValueTracking.cpp (revision 195222)
+++ lib/Analysis/ValueTracking.cpp (working copy)
@@ -2008,6 +2008,9 @@
const LoadInst *LI = cast<LoadInst>(Inst);
if (!LI->isUnordered())
return false;
+ // Speculating a load may create a race that did not exist in the source.
+ if
(LI->getParent()->getParent()->hasFnAttribute(Attribute::SanitizeThread))
+ return false;
return LI->getPointerOperand()->isDereferenceablePointer();
}
case Instruction::Call: {
Original comment by konstant...@gmail.com
on 20 Nov 2013 at 8:12
Should be fixed by http://llvm.org/viewvc/llvm-project?rev=195324&view=rev
choller@, please try.
Original comment by konstant...@gmail.com
on 21 Nov 2013 at 7:40
I've applied the patch to r192787 (I think that's the last good rev right now
for Firefox) and it seems to have fixed the problem, thanks.
Original comment by decoder...@googlemail.com
on 21 Nov 2013 at 9:18
Turns out there is a whole paper about this kind of compiler bugs.
http://www.di.ens.fr/~zappa/readings/pldi13.pdf
Original comment by konstant...@gmail.com
on 27 Nov 2013 at 8:09
This issue is not a compiler bug per se. It is OK to read a global concurrently
on x86.
Original comment by dvyu...@google.com
on 27 Nov 2013 at 8:25
Yes. The paper is about similar situations which *are* bugs
(e.g. thread-hostile store hoisting).
But the same technique could be used to find tsan-hostile optimizations that
are otherwise correct.
Robin Morisset (one of the authors) told me that they've seen a few of those
cases
which were false positives for them.
Original comment by konstant...@gmail.com
on 27 Nov 2013 at 8:28
Original issue reported on code.google.com by
dvyu...@google.com
on 19 Nov 2013 at 3:10