<html>
    <head>
      <base href="http://llvm.org/bugs/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW --- - Incorrectly clobbering stack slot for a local variable used after longjmp"
   href="http://llvm.org/bugs/show_bug.cgi?id=21183">21183</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Incorrectly clobbering stack slot for a local variable used after longjmp
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>MacOS X
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Common Code Generator Code
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>glider@google.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>kcc@google.com, llvmbugs@cs.uiuc.edu
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>For the following class method (see decoder.ii attached) Clang appears to
generate incorrect code:

  void decode() {
    PNGImageDecoder* decoder =
        static_cast<PNGImageDecoder*>(wk_png_get_progressive_ptr(m_void));
    const char* segment;
    if (setjmp(m_png->jmpbuf)) {
      decoder->setFailed();
      return;
    }   
    while (true) {
      getSomeData(segment, m_readOffset);
      m_readOffset++;
      wk_png_process_data(m_info, segment);
      if (decoder->ImageDecoder::isSizeAvailable())
        return;
    }   
  }

$ clang++ -O3 -gdwarf-2 -fvisibility=hidden  -mmacosx-version-min=10.6 -arch
i386  -std=gnu++11 -fno-rtti -fno-exceptions -fvisibility-inlines-hidden
-fno-threadsafe-statics -fsanitize=address -mllvm -asan-globals=0
-gline-tables-only -c decoder.ii -o decoder.o

# See decoder.o.dump attached.
$ gobjdump -rd decoder.o

00000260 <__ZN14PNGImageReader6decodeEv>:
...
 2f2:   e8 09 fd ff ff          call   0 <__ZN15PNGImageDecoder6decodeEv>
                        2f3: DISP32     _wk_png_get_progressive_ptr
 2f7:   89 44 24 0c             mov    %eax,0xc(%esp)
...
 319:   e8 e2 fc ff ff          call   0 <__ZN15PNGImageDecoder6decodeEv>
                        31a: DISP32     _setjmp
 31e:   85 c0                   test   %eax,%eax
 320:   74 41                   je     363
<__ZN14PNGImageReader6decodeEv+0x103>
 322:   8b 54 24 0c             mov    0xc(%esp),%edx
...
 341:   8b 02                   mov    (%edx),%eax
 343:   83 c0 04                add    $0x4,%eax
 346:   89 c1                   mov    %eax,%ecx
...
 35c:   ff 10                   call   *(%eax)
 35e:   e9 6a 01 00 00          jmp    4cd
<__ZN14PNGImageReader6decodeEv+0x26d>
 363:   89 7c 24 14             mov    %edi,0x14(%esp)
...
 36e:   8b 44 24 0c             mov    0xc(%esp),%eax
 372:   8d 88 89 00 00 00       lea    0x89(%eax),%ecx
 378:   89 4c 24 08             mov    %ecx,0x8(%esp)
 37c:   8d 7e 0c                lea    0xc(%esi),%edi
 37f:   83 c6 08                add    $0x8,%esi
 382:   89 74 24 10             mov    %esi,0x10(%esp)
 386:   05 8a 00 00 00          add    $0x8a,%eax
 38b:   89 44 24 0c             mov    %eax,0xc(%esp)
 38f:   90                      nop

In the assembly above the value of |decoder| is stored in 0xc(%esp) before the
call to setjmp().
If setjmp() returns non-zero (i.e. after longjmp()) then |decoder| is loaded
from the stack slot and dereferenced.
But if setjmp returns zero then in the infinite loop the value of |decoder| is
loaded (at address 36e), incremented by 0x8a and stored back to the stack slot
0xc(%esp) (at address 38b).

Because the infinite loop calls getSomeData() and wk_png_process_data() which
may potentially call longjmp(), I believe that such optimization is incorrect
and 0xc(%esp) should not be clobbered.
Note that |decoder| isn't being changed between setjmp() and longjmp(), so the
following part of the C11 Standard (7.13.2.1) does not apply:

<span class="quote">> All accessible objects have values, and all other components of the abstract machine249)
> have state, as of the time the longjmp function was called, except that the values of
> objects of automatic storage duration that are local to the function containing the
> invocation of the corresponding setjmp macro that do not have volatile-qualified type
> and have been changed between the setjmp invocation and longjmp call are
> indeterminate.</span ></pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>