[llvm-bugs] [Bug 47835] New: [coroutines] Compiler incorrectly caches thread_local address across suspend-points

via llvm-bugs llvm-bugs at lists.llvm.org
Tue Oct 13 13:45:02 PDT 2020


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

            Bug ID: 47835
           Summary: [coroutines] Compiler incorrectly caches thread_local
                    address across suspend-points
           Product: clang
           Version: trunk
          Hardware: PC
                OS: All
            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

The clang compiler is incorrectly caching the address of thread_local variables
across a suspend-point. It's possible that a coroutine could suspend and later
resume on a different thread, however, which could mean that the thread_local
instance from another thread might be accessed.

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

For example compile the following program with: -std=c++20 -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() {}
  };
};

thread_local int tls_variable = 0;

static task resuming_on_new_thread(std::thread& out) {
  int* i = &tls_variable;

  co_await switch_to_new_thread(out);

  int* j = &tls_variable;

  std::puts((i == j) ? "tls_variable address was same" : "tls_variable address
was different");
}

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


Expected output: "tls_variable address was different"
Actual output: "tls_variable address was same"

If you compile with -O0 then it correctly outputs "tls_variable address was
different".

-- 
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/3af6ef90/attachment-0001.html>


More information about the llvm-bugs mailing list