-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Fix long-standing soundness hole in rethrows checking #36007
Conversation
The body is not type checked, so we check effects on it anyway.
Once the soundness hole in https://bugs.swift.org/browse/SR-680 is fixed, we need this to annotate code where the type checker cannot prove 'rethrows' safely, such as the implementation of DispatchQueue.sync in stdlib/public/Darwin/Dispatch/Queue.swift.
…ness hole Also let's make use of the Result type while we're here.
c8cc9f5
to
c75c800
Compare
|
@swift-ci Please smoke test |
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.
Amazing. Thanks!
A rethrows function would still be considered rethrows if one of
its argument functions unconditionally throws. This meant that we
would accept the following, even though it was invalid:
enum MyError : Error {
case bad
}
func rethrowsViaClosure(_ fn: () throws -> ()) rethrows {
try fn()
}
func invalidRethrows(_ fn: () throws -> ()) rethrows {
try rethrowsViaClosure { throw MyError.bad }
}
invalidRethrows()
The problem was simple. When visiting a function argument in
rethrows analysis, we would always just drop the result of
the classification walk on the floor, which meant that we
returned ThrowingKind::RethrowingOnly instead of possibly
returning ThrowingKind::Throws.
Fixes https://bugs.swift.org/browse/SR-680 / rdar://problem/27868617.
a1df402
to
da2b0cd
Compare
|
@swift-ci Please test |
|
@swift-ci Please test source compatibility |
|
Build failed |
|
apple/swift-corelibs-foundation#2983 |
|
Build failed |
|
Build failed |
|
Build failed |
|
The methods changed in Dispatch and Foundation seem like very reasonable things for end users to do also. While surely rare, my understanding of Is there no less invasive change to the compiler which wouldn't prohibit these legitimate uses without depending on an underscored attribute? |
|
@xwu They're reasonable things to do, but the workaround people used was kind of silly and just emergent behavior from this bug. You could do this: But not this: If the bug hadn't existed in the first place, nobody would be relying on it the way they are today. The reason that the bug is bad is that you can introduce a runtime crash without realizing it through incorrect usage of Instead of an underscored attribute, we could instead formalize it by introducing a new |
|
Looks like GRDB in the source compat suite relies on this bug also: In this case though, it doesn't appear they're doing anything unsafe. Instead, they're calling a |
|
@xwu I wrote up a pitch for |
| @@ -624,6 +624,11 @@ SIMPLE_DECL_ATTR(reasync, AtReasync, | |||
| ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove, | |||
| 110) | |||
|
|
|||
| SIMPLE_DECL_ATTR(_rethrowsUnchecked, RethrowsUnchecked, | |||
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.
It would be valuable to land this attribute before the checker changes so that code that relies on the current behaviour (such as DispatchQueue) has an opportunity to migrate.
This would make sense to me—that, or some scoped bridging mechanism to allow an engineer to say "I'm going to call an intermediate function that can't throw an error itself (e.g. because it's If nothing else, we could reserve the Edit: I commented in the |
A rethrows function would still be considered rethrows if one of
its argument functions unconditionally throws. This meant that we
would accept the following, even though it was invalid:
The problem was simple. When visiting a function argument in
rethrows analysis, we would always just drop the result of
the classification walk on the floor, which meant that we
returned
ThrowingKind::RethrowingOnlyinstead of possiblyreturning
ThrowingKind::Throws.Since the Dispatch overlay was relying on this hole in the
implementation of
DispatchQueue.sync, I also added a@_rethrowsUncheckedattribute to bypass rethrows checkingentirely for rare cases like this.
Fixes https://bugs.swift.org/browse/SR-680 / rdar://problem/27868617.