Skip to content

[Concurrency] Nest stack traffic in withValue. #65274

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
Apr 19, 2023

Conversation

nate-chandler
Copy link
Contributor

Because _taskLocalValuePush and _taskLocalValuePop can result in calls to swift_task_alloc and swift_task_dealloc respectively, and because the compiler hasn't been taught about that (e.g. SILInstruction::isAllocatingStack, SILInstruction::isDeallocatingStack, etc), calling them (push and pop) from a function which makes use the stack for dynamically sized allocations can result in violations of stack discipline of the form

swift_task_alloc // allocates %ptr_1
copy_value_witness // copies into %ptr_1
swift_task_localValuePush // calls swift_task_alloc and allocates %ptr_2
swift_task_dealloc // deallocates %ptr_1
swift_task_localValuePop // calls swift_task_dealloc and deallocates %ptr_2

Avoid the problem by not allocating dynamically sized stack space in the function which calls _taskLocalValuePush and _taskLocalValuePop. Split the calls to those functions into withValueImpl function which takes its argument __owned. Call that function from withValue, ensuring that the necessary copy (to account for the fact that withValue takes its argument __guaranteed but _taskLocalValuePush takes its __owned) and associated stack traffic occur in withValue.

Still, allow withValueImpl to be inlined. The stack nesting will be preserved across it.

rdar://107275872

@nate-chandler
Copy link
Contributor Author

@swift-ci please test

Copy link
Contributor

@ktoso ktoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the investigating and the fix!

@nate-chandler nate-chandler marked this pull request as ready for review April 19, 2023 01:30
Because `_taskLocalValuePush` and `_taskLocalValuePop` can result in calls
to `swift_task_alloc` and `swift_task_dealloc` respectively, and because
the compiler hasn't been taught about that (e.g.
`SILInstruction::isAllocatingStack`,
`SILInstruction::isDeallocatingStack`, etc), calling them (push and pop)
from a function which makes use the stack for dynamically sized
allocations can result in violations of stack discipline of the form

```
swift_task_alloc // allocates %ptr_1
copy_value_witness // copies into %ptr_1
swift_task_localValuePush // calls swift_task_alloc and allocates %ptr_2
swift_task_dealloc // deallocates %ptr_1
swift_task_localValuePop // calls swift_task_dealloc and deallocates %ptr_2
```

Avoid the problem by not allocating dynamically sized stack space in the
function which calls `_taskLocalValuePush` and `_taskLocalValuePop`.
Split the calls to those functions into `withValueImpl` function which
takes its argument `__owned`.  Call that function from `withValue`,
ensuring that the necessary copy (to account for the fact that withValue
takes its argument `__guaranteed` but `_taskLocalValuePush` takes its
`__owned`) and associated stack traffic occur in `withValue`.

Still, allow `withValueImpl` to be inlined.  The stack nesting will be
preserved across it.

rdar://107275872
@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@nate-chandler
Copy link
Contributor Author

@swift-ci please test macOS platform

@nate-chandler nate-chandler merged commit d20b8d2 into swiftlang:main Apr 19, 2023
@nate-chandler nate-chandler deleted the rdar107275872 branch April 19, 2023 18:52
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.

3 participants