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
[SR-12268] Closure value in mirror crashes #54696
Comments
@swift-ci create |
Here's a simplified reproducer:
This crashes in various ways: I've seen it crash in |
Note: #56720 is another variation of this. |
tbkka
added a commit
to tbkka/swift
that referenced
this issue
Jul 9, 2022
The Swift compiler uses various calling conventions for closures depending on context. This context disappears when you try to use Mirror to reflect a closure-valued property, which can make the closure un-callable. There doesn't seem to be any good solution to this, unless we dictate that a closure's ABI is determined by it's type, which we've so far been unwilling to guarantee. So instead, this PR erases closure values during reflection, making it impossible to directly reflect closures. Note that the field still appears in the reflection list, but the value is replaced with `()` (the empty tuple, aka Void). ``` struct A { var prop: () -> Int } let a = A { return 7 } let m = Mirror(reflecting: a) let c = m.children.first!.value let p = c as? () -> Int // Before this PR, the cast above would succeed, // but the call below could crash. p() ``` Note however, that it _does_ work to put a closure in an `Any` or other container, reflect that container, and then access the closure. (In this case, the compiler has full visibility into all direct accesses to the closure.) ``` struct B { var prop: Any } let b = B(prop: { return 7 } as Any) let m = Mirror(reflecting: b) let c = m.children.first!.value let p = c as? () -> Int // This always worked p() // This always succeeded ``` Resolves rdar://59791962, SR-12268, SR-14362, apple#54696
tbkka
added a commit
to tbkka/swift
that referenced
this issue
Feb 1, 2023
The Swift compiler uses various calling conventions for closures depending on context. This context disappears when you try to use Mirror to reflect a closure-valued property, which can make the closure un-callable. There doesn't seem to be any good solution to this, unless we dictate that a closure's ABI is determined by it's type, which we've so far been unwilling to guarantee. So instead, this PR erases closure values during reflection, making it impossible to directly reflect closures. Note that the field still appears in the reflection list, but the value is replaced with `()` (the empty tuple, aka Void). ``` struct A { var prop: () -> Int } let a = A { return 7 } let m = Mirror(reflecting: a) let c = m.children.first!.value let p = c as? () -> Int // Before this PR, the cast above would succeed, // but the call below could crash. p() ``` Note however, that it _does_ work to put a closure in an `Any` or other container, reflect that container, and then access the closure. (In this case, the compiler has full visibility into all direct accesses to the closure.) ``` struct B { var prop: Any } let b = B(prop: { return 7 } as Any) let m = Mirror(reflecting: b) let c = m.children.first!.value let p = c as? () -> Int // This always worked p() // This always succeeded ``` Resolves rdar://59791962, SR-12268, SR-14362, apple#54696
Closed
3 tasks
tbkka
added a commit
to tbkka/swift
that referenced
this issue
Aug 17, 2023
The Swift compiler uses various calling conventions for closures depending on context. This context disappears when you try to use Mirror to reflect a closure-valued property, which can make the closure un-callable. There doesn't seem to be any good solution to this, unless we dictate that a closure's ABI is determined by it's type, which we've so far been unwilling to guarantee. So instead, this PR erases closure values during reflection, making it impossible to directly reflect closures. Note that the field still appears in the reflection list, but the value is replaced with `()` (the empty tuple, aka Void). ``` struct A { var prop: () -> Int } let a = A { return 7 } let m = Mirror(reflecting: a) let c = m.children.first!.value let p = c as? () -> Int // Before this PR, the cast above would succeed, // but the call below could crash. p() ``` Note however, that it _does_ work to put a closure in an `Any` or other container, reflect that container, and then access the closure. (In this case, the compiler has full visibility into all direct accesses to the closure.) ``` struct B { var prop: Any } let b = B(prop: { return 7 } as Any) let m = Mirror(reflecting: b) let c = m.children.first!.value let p = c as? () -> Int // This always worked p() // This always succeeded ``` Resolves rdar://59791962, SR-12268, SR-14362, apple#54696
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Environment
Swift 5.1
Additional Detail from JIRA
md5: 05f52733774e73a6ed86c94ce0aed672
Issue Description:
Mirrors that contain closures can crash in unexpected ways. For example, run the following code:
And you'll get a bad access fatal error when invoking
bar
despite the fact that it was cast just fine.The text was updated successfully, but these errors were encountered: