-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Concurrency] Fix races/overflows in TaskGroup implementation. #81814
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
Conversation
@swift-ci please test |
@@ -378,7 +378,7 @@ public func _unsafeInheritExecutor_withThrowingDiscardingTaskGroup<GroupResult>( | |||
discardResults: true | |||
) | |||
|
|||
let _group = Builtin.createTaskGroupWithFlags(flags, GroupResult.self) | |||
let _group = Builtin.createTaskGroupWithFlags(flags, Void.self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch, good
old.status, old.completingPendingReadyWaiting(this).status, | ||
/*success*/ std::memory_order_relaxed, | ||
/*failure*/ std::memory_order_relaxed); | ||
/*failure*/ std::memory_order_relaxed)) { | ||
} // Loop until the compare_exchange succeeds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -1796,77 +1803,81 @@ reevaluate_if_taskgroup_has_results:; | |||
auto waitHead = waitQueue.load(std::memory_order_acquire); | |||
|
|||
// ==== 2) Ready task was polled, return with it immediately ----------------- | |||
if (assumed.readyTasks(this)) { | |||
while (assumed.readyTasks(this)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
statusCompletePendingReadyWaiting(), offer(), and poll() did a one-off compare_exchange_strong which could fail if the group was concurrently cancelled. Put these into loops so that they are retried when needed. DiscardingTaskGroup creation passed the group result type as the task result type. waitAll() would then use the group result type when collecting task results. Since the task result type is always Void in this case, this would overflow the result buffer if the group result type was larger. This often works as it writes into the free space of the task allocator, but can crash if it happens to be at the end of a page or the group result type is particularly large. rdar://151663730
@swift-ci please test |
Looks like macOS hit the issue fixed by #81830 and everything was good otherwise. Retrying. |
@swift-ci please smoke test macos platform |
statusCompletePendingReadyWaiting(), offer(), and poll() did a one-off compare_exchange_strong which could fail if the group was concurrently cancelled. Put these into loops so that they are retried when needed.
DiscardingTaskGroup creation passed the group result type as the task result type. waitAll() would then use the group result type when collecting task results. Since the task result type is always Void in this case, this would overflow the result buffer if the group result type was larger. This often works as it writes into the free space of the task allocator, but can crash if it happens to be at the end of a page or the group result type is particularly large.
rdar://151663730