Skip to content

5.9.0: [stdlib] Delete bad @_effects(readonly) annotation #68221

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

nate-chandler
Copy link
Contributor

@nate-chandler nate-chandler commented Aug 30, 2023

Description: Programs built with release/5.9 crash when back-deploying to before 10.15 if they use an empty dictionary literal.

Since 2014, Dictionary.init(dictionaryLiteral:) has been annotated @_effects(readonly). Among other things, that annotation means the function must not release any values. At the time, the default convention for inits was that they "borrowed" the values passed to them--they could not release them. Subsequently, that default convention changed so that inits instead "consumed" the values passed to them--starting then, the inits released the values if they were not consumed by some other mechanism (storing them, calling some other function which consumed them, etc.). From that time on, this annotation has been incorrect.

In release/5.9, this incorrectness was exposed as a runtime crash. In particular, given a program involving a class with a field of dictionary type which is initialized to be the empty dictionary, building that program with release/5.9 and running that program on pre-10.15 will result in a runtime crash.

Here's what's happening: the empty dictionary literal [:] is turned into a call Dictionary.init(dictionaryLiteral: []). The empty array is passed to Dictionary.init which consumes it. Because Dictionary.init does not store (or otherwise consume) the empty array, it releases it. Because Dictionary.init consumes its argument, when compiling the function containing the call to it (i.e. containing [:]), the compiler retains the empty array [] that's passed to it. Now, to decrease unnecessary ARC traffic, the compiler sinks retains and hoists releases so that they can be eliminated altogether. When the compiler sinks the retain of [], it is allowed to move it past the call to Dictionary.init because the call is explicitly annotated @_effects(readonly) which means that it can't release the empty array. Because Dictionary.init actually releases its argument [], the call to retain is a use-after-free.

The crashes only occur on older macOSes because more recently (since 2019) empty collection singletons like the empty array have been made immortal.
Risk: Very low. The fix is to delete an annotation from a stdlib function. The annotation only communicates (false) information about optimization opportunities to the compiler.
Scope: Very narrow. Deletes a single line of code from a stdlib function.
Reward: High. Fixes runtime crashes for many programs built with release/5.9 compilers when running on old macOSes.
Origin: Primeval.
Original PR: #68223
Reviewed By: Andrew Trick ( @atrick )
Testing: Added a test demonstrating that retain of [] is not sunk to below the call to Dictionary.init. Verified that runtime crash doesn't occur with fix applied.
Resolves: rdar://114699006

`Dictionary.init(dictionaryLiteral:)` was annotated
`@_effects(readonly)` which means among other things that it doesn't
release any references. Being an init, however, it consumes its
arguments, and so does in fact release.

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

@swift-ci please test

@nate-chandler
Copy link
Contributor Author

@swift-ci please build toolchain

@nate-chandler nate-chandler changed the title [stdlib] Delete bad @_effects(readonly) annotation 5.9.0: [stdlib] Delete bad @_effects(readonly) annotation Aug 30, 2023
@nate-chandler
Copy link
Contributor Author

hudson.AbortException: missing workspace /Users/ec2-user/jenkins/workspace/swift-PR-macos on macos-node-i-09123be3f508fd6ae

@swift-ci please test macos platform

@nate-chandler nate-chandler marked this pull request as ready for review August 31, 2023 13:19
@nate-chandler nate-chandler requested a review from a team as a code owner August 31, 2023 13:19
@nate-chandler nate-chandler merged commit 404a69d into swiftlang:release/5.9.0 Aug 31, 2023
@nate-chandler nate-chandler deleted the cherrypick/release/5.9.0/rdar114699006 branch August 31, 2023 16:24
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