http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46143

           Summary: __attribute__((optimize)) emits wrong code
           Product: gcc
           Version: 4.5.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: scov...@gmail.com


Created attachment 22129
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=22129
Test case showing wrong code with __attribute__((optimize(0)))

Applying '__attribute__((optimize(0)))' to a function causes it to call the
wrong variant/clone of an optimized callee that returns a struct by value.

The attached test case reproduces the problem when compiled with `g++ -O3 -DBUG
bug.cpp' 

The problem seems to be the way gcc optimizes return-by-value. The statement:

iterator it = v.begin()

becomes

tmp = alloca(sizeof(iterator))
vector::begin(tmp, &v)
iterator it(*(iterator*)tmp)

However, gcc actually calls the wrong variant of vector::begin, with the latter
thinking its first argument is &v._M_impl._M_start (an iterator to be copied)
and which has optimized away the struct completely to return only a pointer. It
therefore allocates a temporary and proceeds to "initialize" it using the
(uninitialized) return-value it was passed, then returns the temporary's
contents to the caller (main). As a result, 'it' points to whatever happened to
be on the stack at the time of the call. 

Note that the test case smashes the stack only to make the symptoms consistent;
the bug remains with or without it.

The relevant disassembly follows:

main:
        # call vector::begin(&rval_ptr, &v)
        subq    $24, %rsp        # allocate hidden tmp1
        movq    v(%rip), %rdx
        movq    %rdx, %rsi       # second arg is &v
        movq    %rsp, %rdi       # first arg is &tmp1
        call    _ZNSt6vectorIP3fooSaIS1_EE5beginEv.clone.1
        ...

_ZNSt6vectorIP3fooSaIS1_EE5beginEv.clone.1:
        subq    $24, %rsp        # allocate hidden tmp2
        movq    %rdi, %rsi       # second arg expects &v but gets &tmp1
        movq    %rsp, %rdi       # first arg is &tmp2
        call   
_ZN9__gnu_cxx17__normal_iteratorIPP3fooSt6vectorIS2_SaIS2_EEEC2ERKS3_.clone.0
        movq    (%rsp), %rax     # return the contents of tmp2
        addq    $24, %rsp
        ret

_ZN9__gnu_cxx17__normal_iteratorIPP3fooSt6vectorIS2_SaIS2_EEEC2ERKS3_.clone.0:
        movq    %rsi, (%rdi)     # tmp2 = tmp1
        ret

Reply via email to