[llvm-bugs] [Bug 52440] New: miscompilation of for loop with a condition scope and continue statement

via llvm-bugs llvm-bugs at lists.llvm.org
Mon Nov 8 11:28:48 PST 2021


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: unassignedclangbugs at nondot.org
          Reporter: shevitz at lanl.gov
                CC: blitzrakete at gmail.com, dgregor at apple.com,
                    erik.pilkington at gmail.com, llvm-bugs at lists.llvm.org,
                    richard-llvm at 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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20211108/cef69d77/attachment-0001.html>


More information about the llvm-bugs mailing list