[LLVMdev] LLVM introduces racy read - Unsafe transformation?

Alexander Potapenko
Tue, 27 Jan 2015 06:22:34 -0000

Unlike C++, LLVM IR has defined semantics in the case of data races. Your
load may return undef (
http://llvm.org/docs/Atomics.html#optimization-outside-atomic), but the
program doesn't have undefined behavior.
On Jan 27, 2015 6:20 AM, <sohachak at mpi-sws.org> wrote:

> Hi,
>
> I agree that the earlier example was already racy due to shared flag
> variable. Sorry for the wrong example. Please ignore it.
>
> I have modified the program as follows. The only shared variable is
'a'
> and the following is a non-racy program.
>
> int a;
>
> int readA(bool flag) {
>  int r=0;
>   if(flag) {
>     r = a;
>  }
> return r;
> }
>
> void writeA(){
>   a = 42;
> }
>
> int main() {
>
>  bool flag = false;
>  thread first (writeA);
>  thread second (readA, flag);
>
>  first.join();
>  second.join();
>
>  return 0;
> }
>
> The generated LLVM IR
>
> ; Function Attrs: nounwind readonly uwtable
> define i32 @_Z5readAb(i1 zeroext %flag) #3 {
> entry:
>   %0 = load i32* @a, align 4
>   %. = select i1 %flag, i32 %0, i32 0
>   ret i32 %.
> }
>
> ; Function Attrs: nounwind uwtable
> define void @_Z6writeAv() #4 {
> entry:
>   store i32 42, i32* @a, align 4
>   ret void
> }
>
> :
>
> In the generated IR load(a) is independent of flag value which is not the
> case in the source program. Hence there is an introduced race between
> load(a) and store(a) operations when readA() and writeA() runs
> concurrently.
>
> Regards,
> soham
>
>
> > On 26 Jan 2015, at 15:22, sohachak at mpi-sws.org wrote:
> >>
> >> The source program has no data race if flag=false. But the target
> >> program
> >> is racy due to the introduced load(a) operation.
> >>
> >> This is a benign race since the load(a) is used only when
flag=true.
> >>
> >> However, according to the C11/C++11 consistency model the
semantics of a
> >> racy program is undefined and may have arbitrary behavior.
> >
> > It's not clear to me that this is correct.  Neither variable is
atomic
> and
> > so loads do not establish happens-before edges.  The load of a is not
> > observable and so is safe to hoist.  According to the C[++]11 model
the
> > transformed version appears correct.  There is no guarantee of
> > serialisation of the loads of flag and a, because neither is atomic.
> >
> > It's not actually clear to me that the original is race-free.  If
flag
> > ever transitions from false to true without something else that
> > establishes a happens-before relationship between these two threads
then
> > this is racy.  If flag is always false, then this is not racy and the
> LLVM
> > output is not *observably* racy (the IR does not permit this load to
have
> > observable side effects, and its result is never used).  If flag is
> always
> > true then this is racy.  If flag transitions from true to false
without a
> > happens-before edge, then this is also racy.
> >
> > David
> >
> >
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20150127/ddc00c5b/attachment.html>