Skip to content

[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

Merged
merged 1 commit into from
May 29, 2025

Conversation

mikeash
Copy link
Contributor

@mikeash mikeash commented May 28, 2025

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

@mikeash
Copy link
Contributor Author

mikeash commented May 28, 2025

@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)
Copy link
Contributor

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
Copy link
Contributor

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)) {
Copy link
Contributor

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
@mikeash mikeash force-pushed the taskgroup-fixes branch from 494c3f1 to 5be22fa Compare May 29, 2025 00:58
@mikeash
Copy link
Contributor Author

mikeash commented May 29, 2025

@swift-ci please test

@mikeash mikeash enabled auto-merge May 29, 2025 00:59
@mikeash
Copy link
Contributor Author

mikeash commented May 29, 2025

Looks like macOS hit the issue fixed by #81830 and everything was good otherwise. Retrying.

@mikeash
Copy link
Contributor Author

mikeash commented May 29, 2025

@swift-ci please smoke test macos platform

@mikeash mikeash merged commit c9329db into swiftlang:main May 29, 2025
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants