<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] Clang incorrectly caches result of pthread_self() across coroutine suspend-points"
   href="https://bugs.llvm.org/show_bug.cgi?id=47833">47833</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[coroutines] Clang incorrectly caches result of pthread_self() across coroutine suspend-points
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

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

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

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

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

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

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

        <tr>
          <th>Component</th>
          <td>C++2a
          </td>
        </tr>

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

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

        <tr>
          <th>CC</th>
          <td>blitzrakete@gmail.com, erik.pilkington@gmail.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Godbolt: <a href="https://godbolt.org/z/zYfvaM">https://godbolt.org/z/zYfvaM</a>

Compile the following program with: -std=c++20 -fcoroutines-ts -stdlib=libc++
-O2 -pthread

---

#include <experimental/coroutine>
#include <thread>
#include <unistd.h>
#include <pthread.h>

auto switch_to_new_thread(std::thread& out) {
  struct awaitable {
    std::thread* p_out;
    bool await_ready() { return false; }
    void await_suspend(std::experimental::coroutine_handle<> h) {
      std::thread& out = *p_out;
      out = std::thread([h]() mutable {
          h.resume();
        });
    }
    void await_resume() {}
  };
  return awaitable{&out};
}

struct task{
  struct promise_type {
    task get_return_object() { return {}; }
    std::experimental::suspend_never initial_suspend() { return {}; }
    std::experimental::suspend_never final_suspend() noexcept { return {}; }
    void return_void() {}
    void unhandled_exception() {}
  };
};

static task resuming_on_new_thread(std::thread& out) {
  auto id1 = std::this_thread::get_id();
  auto pthread1 = pthread_self();
  auto pid1 = gettid();

  co_await switch_to_new_thread(out);

  auto id2 = std::this_thread::get_id();
  auto pthread2 = pthread_self();
  auto pid2 = gettid();

  std::puts((id1 == id2) ? "this_thread::get_id() was same" :
"this_thread::get_id() was different");
  std::puts((pid1 == pid2) ? "gettid() was same" : "gettid() was different");
  std::puts((pthread1 == pthread2) ? "pthread_self() was same" :
"pthread_self() was different");
}

int main() {
  std::thread out;
  resuming_on_new_thread(out);
  out.join();
}

----

Expected output:
---
this_thread::get_id() was different
gettid() was different
pthread_self() was different

Actual output:
---
this_thread::get_id() was same
gettid() was different
pthread_self() was same


The compiler generates code that calls the pthread_self() function once at the
start of the coroutine and then caches the result in the coroutine frame and
reloads the cached value after the coroutine resumes on another thread, leading
to the second call to pthread_self() seemingly returning the wrong value.

This also affects std::this_thread::get_id(), which is a thin-wrapper over
pthread_self(), and so if get_id() is inlined into the coroutine then it hits
the same problem. If get_id() is not inlined into the coroutine (eg. when using
-O1) then the second std::this_thread::get_id() gives the correct result.</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>