Skip to content

[6.0] SILGen: Move error values into indirect error returns in proper order with cleanups #73093

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

jckarter
Copy link
Contributor

@jckarter jckarter commented Apr 17, 2024

Explanation: Fixes a bug where a closure literal that throws untyped errors or another "loadable" error type but which appears in an argument context where the callee expects an indirect generic error return would lead to a crash or miscompile.
Scope: Bug fix for typed throws.
Issue: rdar://126576356
Original PR: #73092
Risk: Low. Fixes a targeted use case.
Testing: Swift CI, test case from issue
Reviewer: @eeckstein

… with cleanups.

There's an unfortunate layering difference in the cleanup order between address-only
and loadable error values during `catch` pattern matching: for address-only values,
the value is copied into a temporary stack slot, and the stack slot is cleaned up
on exit from the pattern match, meaning the value must be moved into the error return
slot on the "no catch" case before cleanups run. But if it's a loadable value, then
we borrow it for the duration of the switch, and the borrow is released during cleanup
on exit from the pattern match, so the value must be forwarded after running cleanups.

The way the code is structured, it handles these cases properly when the convention of
the function being emitted is in sync with the fundamental properties of the error type
(when the error type is loadable and the error return is by value, or when the error
type is address-only and the error return is indirect, in other words). But when
a closure literal with a loadable error type is emitted in an argument context that
expects a function with an indirect error return, we would try to forward the loadable
error value into the error return slot while a borrow is still active on it, leading
to verifier errors. Defer forwarding the value into memory until after cleanups are
popped, fixing rdar://126576356.

A tidier solution might be to always emit the function body to use a bbarg on the
throw block to pass the error value from the body emission to the epilog when the
type is loadable, deferring the move into memory to the epilog block. This would
make the right behavior fall out of the existing implementation, but would require
a bit more invasive changes (pretty much everywhere that checks IndirectErrorReturn
would need to check a different-tracked AddressOnlyErrorType bit instead or in
addition). This change is more localized.
@jckarter jckarter requested a review from a team as a code owner April 17, 2024 22:21
@jckarter
Copy link
Contributor Author

@swift-ci Please test

Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

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

lgtm

@jckarter jckarter merged commit 4e30159 into swiftlang:release/6.0 Apr 18, 2024
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