Skip to content
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

[exec.schedule.from] Potential access to destroyed state in impls-for::complete #233

Closed
lewissbaker opened this issue May 20, 2024 · 2 comments
Labels
bug Something isn't working P0 pending-wg21 A paper or an LWG issue exits processed processed in a meeting wording

Comments

@lewissbaker
Copy link
Collaborator

The current specification of schedule_from algorithm has the following definition for impls-for<schedule_form_t>::complete:

[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void {
  using result_t = decayed-tuple<Tag, Args...>;
  constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>;

  TRY-EVAL(std::move(rcvr), [&]() noexcept(nothrow) {
    state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
  }());

  if (state.async-result.valueless_by_exception())
    return;
  if (state.async-result.index() == 0)
    return;

  start(state.op-state);
};

The call to TRY-EVAL here will invoke set_error() on the receiver if the construction of result_t throws an exception.
As the call to set_error() can potentially end up destroying the operation-state, the subsequent access of state.async-result.valueless_by_exception() is potentially accessing a dangling reference to state.

Instead, we need to have this function return; after set_error() is called. This may mean we need to directly define the expansion of TRY-EVAL instead of using the macro.

e.g. something like:

[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept -> void {
  using result_t = decayed-tuple<Tag, Args...>;
  constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>;

  try {
    state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
  } catch (...) {
    if constexpr (!nothrow) {
      execution::set_error(std::move(rcvr), std::current_exception());
      return;
    }
  }

  assert(state.async-result.index() != 0);
  assert(!state.async-result.valueless_by_exception());

  start(state.op-state);
};
@lewissbaker lewissbaker added wording bug Something isn't working labels May 20, 2024
@lewissbaker lewissbaker added the P0 label Jul 4, 2024
@lewissbaker
Copy link
Collaborator Author

A resolution to this issue has been proposed in https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3396r0.html

@inbal2l inbal2l added processed processed in a meeting pending-wg21 A paper or an LWG issue exits labels Oct 23, 2024
@lewissbaker
Copy link
Collaborator Author

The proposed resolution was adopted in the Wroclaw meeting.
See https://wg21.link/P3396R1

The resulting wording should now be:

[]<class Tag, class... Args>(auto, auto& state, auto& rcvr, Tag, Args&&... args) noexcept
    -> void {
  using result_t = decayed-tuple<Tag, Args...>;
  constexpr bool nothrow = is_nothrow_constructible_v<result_t, Tag, Args...>;
  try {
        state.async-result.template emplace<result_t>(Tag(), std::forward<Args>(args)...);
  } catch (...) {
    if constexpr (!nothrow) {
      set_error(std::move(rcvr), current_exception());
      return;
    }
  }

  start(state.op-state);
};

Note that this still has the unresolved issue #304

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working P0 pending-wg21 A paper or an LWG issue exits processed processed in a meeting wording
Projects
None yet
Development

No branches or pull requests

2 participants