coroutine: fix a use-after-free in maybe_yield #1760
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
maybe_yield_awaiter resumes the coroutine (after it decided to suspend it) by scheduling itself as a task, which -- when executed -- resumes the coroutine.
The awaiter itself is (usually) allocated inside the coroutine frame, and dies after its containing co_await expression is resumed. This is a problem, because the reactor expects tasks to stay alive while they are running. To facilitate current_tasktrace(), a global pointer to the currently running task is needed. Thus, when the reactor starts executing a task, it saves a pointer to it in reactor::_current_task.
Since the awaiter task dies immediately after returning control to its parent, reactor::_current_task is left pointing to some garbage in the coroutine frame and current_tasktrace() will (most likely) segfault when used before the next task switch.
To fix this, we directly schedule the parent coroutine. Making maybe_yield_awaiter a task was an unnecessary indirection anyway.
Refs #1599. It's the same kind of bug.
Fixes #1759