https://bugs.llvm.org/show_bug.cgi?id=52440

            Bug ID: 52440
           Summary: miscompilation of for loop with a condition scope and
                    continue statement
           Product: clang
           Version: unspecified
          Hardware: All
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++
          Assignee: unassignedclangb...@nondot.org
          Reporter: shev...@lanl.gov
                CC: blitzrak...@gmail.com, dgre...@apple.com,
                    erik.pilking...@gmail.com, llvm-bugs@lists.llvm.org,
                    richard-l...@metafoo.co.uk

I believe there is a very obscure miscompilation in clang when compiling a
`for` statement with both a condition scope and a continue statement. I am
including a minimal reproducer along with a .pdf file of the CFG that
demonstrates the problem. 

The essence of the problem is that when there is a condition scope variable, a
continue statement branches to the wrong basic block. Referring to labels
visible in the CFG of the minimal_bug.pdf file, the continue statement in the
for body sets `%cleanup.dest.slot` to `4` which goes to the `%cleanup` basic
block. The `%cleanup` block does cleanups, then the code branches to the
`%for.inc` which sets `%cleanup.dest.slot% to 0 then branches back to
`%cleanup` and performs cleanups a second time. In short the destructor of a
non trivial condition scope variable is called twice because of the cycle in
the CFG between `%cleanup` and `%for.inc`. 

While calling a destructor twice on the same object doesn't seem to inherently
cause a problem, a double free causes a core dump. The minimal_bug example is
constructed to cause a double free of a non-trivial condition scope variable so
the executable core dumps. 

The solution to the miscompilation is to have the continue statement branch to
`%for.inc` rather than `%cleanup`. That way the cleanups are only done once.

The bug is obvious at optimization level 0, but I believe is there at all
optimization levels.

I am uploading a .pdf of the CFG generated by the minimal reproducer
demonstrating the bug. I seem to be able to only include one attachment, so I
will include the source inline:

//////////////////////////////////////////////////////////////////////
// minimal_bug.cpp
// This is a reproducer for the double free core dump in "for" codegen

struct S2 {
    int x;
};

struct S {
    S(int x=0):x(x) {s2=new S2;}
    ~S() {delete s2;}
    int x;
    S2* s2;
    operator bool() {return x<5;}
};

int main () {
    for (int i = 4; S s{i}; ++i) continue;
    return 0;
} 
//////////////////////////////////////////////////////////////////////

compile with (The executable will core dump):

clang++ -fno-exceptions -O0 minimal_bug.cpp

To generate the IR:

clang++ -fno-exceptions -O0 -S -emit-llvm minimal_bug.cpp

To generate the CFG:

opt -dot-cfg minimal_bug.ll
dot -Tpdf -o minimal_bug.pdf .main.dot -Gsize=8,10.5\!

Regards,
Danny

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to