Skip to content

Clang miscompilation producing double destroy coro local variable #109542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kelbon opened this issue Sep 21, 2024 · 6 comments
Open

Clang miscompilation producing double destroy coro local variable #109542

kelbon opened this issue Sep 21, 2024 · 6 comments
Labels

Comments

@kelbon
Copy link
Contributor

kelbon commented Sep 21, 2024

https://godbolt.org/z/KqqK1aqv6

struct inplace_generator_promise {
  using handle_type = std::coroutine_handle<inplace_generator_promise>;

  handle_type get_return_object() noexcept {
    return handle_type::from_promise(*this);
  }

  std::suspend_always yield_value(int) noexcept {
    return {};
  }

  static constexpr std::suspend_never initial_suspend() noexcept {
    return {};
  }

  std::suspend_always final_suspend() const noexcept {
    return {};
  }
  static constexpr void return_void() noexcept {
  }
  [[noreturn]] static void unhandled_exception() {
    throw;
  }
};

struct inplace_generator {
  using promise_type = inplace_generator_promise;
  using handle_type = std::coroutine_handle<promise_type>;

  handle_type handle;

  inplace_generator(std::coroutine_handle<promise_type> handle) noexcept : handle(handle) {
  }

  ~inplace_generator() {
    handle.destroy();
  }
};

struct dctor {
  dctor() {
    std::cout << "CREATED\n";
  }
  dctor(dctor&&) = delete;
  void operator=(dctor&&) = delete;
  ~dctor() {
    std::cout << "DELETED\n";
  }
};
inplace_generator starter(){
// double destroyed, firstly after throw, second in handle.destroy(), must not be destroyed in handle.destroy after it
    dctor d; 
    co_yield {};
    throw 0;
}

[[gnu::noinline]] void bug_reproducer() {
    starter().handle.resume();
}
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Sep 21, 2024
@EugeneZelenko EugeneZelenko added coroutines C++20 coroutines and removed clang Clang issues not falling into any other category labels Sep 21, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 21, 2024

@llvm/issue-subscribers-coroutines

Author: None (kelbon)

https://godbolt.org/z/KqqK1aqv6
struct inplace_generator_promise {
  using handle_type = std::coroutine_handle&lt;inplace_generator_promise&gt;;

  handle_type get_return_object() noexcept {
    return handle_type::from_promise(*this);
  }

  std::suspend_always yield_value(int) noexcept {
    return {};
  }

  static constexpr std::suspend_never initial_suspend() noexcept {
    return {};
  }

  std::suspend_always final_suspend() const noexcept {
    return {};
  }
  static constexpr void return_void() noexcept {
  }
  [[noreturn]] static void unhandled_exception() {
    throw;
  }
};

struct inplace_generator {
  using promise_type = inplace_generator_promise;
  using handle_type = std::coroutine_handle&lt;promise_type&gt;;

  handle_type handle;

  inplace_generator(std::coroutine_handle&lt;promise_type&gt; handle) noexcept : handle(handle) {
  }

  ~inplace_generator() {
    handle.destroy();
  }
};

struct dctor {
  dctor() {
    std::cout &lt;&lt; "CREATED\n";
  }
  dctor(dctor&amp;&amp;) = delete;
  void operator=(dctor&amp;&amp;) = delete;
  ~dctor() {
    std::cout &lt;&lt; "DELETED\n";
  }
};
inplace_generator starter(){
// double destroyed, firstly after throw, second in handle.destroy(), must not be destroyed in handle.destroy after it
    dctor d; 
    co_yield {};
    throw 0;
}

[[gnu::noinline]] void bug_reproducer() {
    starter().handle.resume();
}

@kelbon
Copy link
Contributor Author

kelbon commented Sep 22, 2024

I also noticed, that removing [[noreturn]] in minimized version fixes double free

@rnk rnk assigned rnk, zmodem and alanzhao1 and unassigned rnk, zmodem and alanzhao1 Sep 23, 2024
@rnk
Copy link
Collaborator

rnk commented Sep 23, 2024

(Sorry for the noise, I see this is EH-related, which is out of scope for us)

@dtcxzyw
Copy link
Member

dtcxzyw commented Sep 24, 2024

Seems related to #61900. cc @ChuanqiXu9

@ChuanqiXu9
Copy link
Member

Given the current one is not related to optimization, it may not be strictly the same issue. But they may share the solution.

@kelbon
Copy link
Contributor Author

kelbon commented Sep 24, 2024

Im remembering bug in clang, something like:

return a;
label:
foo();

And code was incorrectly deleted as unreachable, now i see, that [[noreturn]] in debug version removes 35% of generateed code. May be just again "unreachable" code deleted, while its reachable?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants