[llvm-bugs] [Bug 47833] New: [coroutines] Clang incorrectly caches result of pthread_self() across coroutine suspend-points

via llvm-bugs llvm-bugs at lists.llvm.org
Tue Oct 13 13:08:20 PDT 2020


https://bugs.llvm.org/show_bug.cgi?id=47833

            Bug ID: 47833
           Summary: [coroutines] Clang incorrectly caches result of
                    pthread_self() across coroutine suspend-points
           Product: clang
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: C++2a
          Assignee: unassignedclangbugs at nondot.org
          Reporter: lewissbaker at gmail.com
                CC: blitzrakete at gmail.com, erik.pilkington at gmail.com,
                    llvm-bugs at lists.llvm.org, richard-llvm at metafoo.co.uk

Godbolt: https://godbolt.org/z/zYfvaM

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.

-- 
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/20201013/d067aa2d/attachment.html>


More information about the llvm-bugs mailing list