<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </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 - [coroutines] coroutine frame constructs overaligned promise objects at wrong offset"
   href="https://bugs.llvm.org/show_bug.cgi?id=43098">43098</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[coroutines] coroutine frame constructs overaligned promise objects at wrong offset
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>new-bugs
          </td>
        </tr>

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

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

        <tr>
          <th>OS</th>
          <td>All
          </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>new bugs
          </td>
        </tr>

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

        <tr>
          <th>Reporter</th>
          <td>lewissbaker@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>htmldeveloper@gmail.com, llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>If a coroutine has a promise_type that has an alignment that is greater than 2
* sizeof(void*) (eg. >= 32 byte alignment on 64-bit platforms) then there is an
inconsistency in the calculation of the promise object offset within the
coroutine frame struct generated in CoroFrame.cpp and the offset claculated by
the lowering of __llvm.coro.promise() in CoroEarly.cpp

This results in a coroutine_handle constructed using
coroutine_handle::from_promise() within the promise_type::get_return_object()
method calculating and incorrect coroutine frame address which then promptly
segfaults if you try to call resume() or destroy() on that coroutine_handle.

See <a href="https://godbolt.org/z/B_SsFR">https://godbolt.org/z/B_SsFR</a>

It appears that when the promise type has alignment greater than 2 *
sizeof(void*) that the code generated by the ramp function continues to
construct the promise object at offset 2 * sizeof(void*) into the coroutine
frame, whereas the __builtin_coro_promise() / llvm.coro.promise() intrinsics
(used by coroutine_handle::promise/from_promise) are using an alignment-padded
offset for the promise relative to the coroutine frame pointer.

This inconsistency causes two problems:
1. Inside the `promise_type::get_return_object()` if you call
coroutine_handle<promise_type>::from_promise() then you will get back a
coroutine_handle that has the wrong address. Attempting to use this handle in
any way to resume/destroy the coroutine will almost certainly lead to an
access-violation as it will be trying to call a function pointer loaded from
potentially uninitialised memory. This seems to be what is happening in the
issue reported by the linked post.

2. If your coroutine type does not call coroutine_handle::from_promise() and
and manages to execute until you hit a suspend-point, then if you try to use
the coroutine_handle passed to await_suspend() to access the promise by calling
the .promise() method then you will receive a reference to a different address
than the one that the promise was constructed at by the coroutine ramp
function.


The problem is possibly in the buildFrameType() function in CoroFrame.cpp.

This calculates the layout of the ABI-stable part of the coroutine frame struct
as follows:

    Type *IndexType = Type::getIntNTy(C, IndexBits);
    Types.push_back(FnPtrTy);
    Types.push_back(FnPtrTy);
    Types.push_back(PromiseType);
    Types.push_back(IndexType);

However, when adding later members to the coroutine frame type it has some
additional logic to deal with adding padding members for alignment which is not
present when adding the members to the ABI-stable section.

      if (unsigned AllocaAlignment = AI->getAlignment()) {
        // If alignment is specified in alloca, see if we need to insert extra
        // padding.
        if (auto PaddingTy = Padder.getPaddingType(Ty, AllocaAlignment)) {
          Types.push_back(PaddingTy);
          Padder.addType(PaddingTy);
        }
      }

Do we need to add this same padding logic when adding the PromiseType and
IndexType members so that the offset calculated for the promise is consistent
with llvm.coro.promise() intrinsic?</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>