diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 8eea8378b28..977c08f987c 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 26.1.2 + +* [swift] Adds a do/catch when a deallocated object calls back to Dart to prevent a crash. + ## 26.1.1 * Updates supported `analyzer` versions to 8.x or 9.x. diff --git a/packages/pigeon/lib/src/generator_tools.dart b/packages/pigeon/lib/src/generator_tools.dart index e75bdfcd1ae..2b687eb632d 100644 --- a/packages/pigeon/lib/src/generator_tools.dart +++ b/packages/pigeon/lib/src/generator_tools.dart @@ -15,7 +15,7 @@ import 'generator.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '26.1.1'; +const String pigeonVersion = '26.1.2'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/lib/src/swift/swift_generator.dart b/packages/pigeon/lib/src/swift/swift_generator.dart index 2f30a35fd4e..93281a19c81 100644 --- a/packages/pigeon/lib/src/swift/swift_generator.dart +++ b/packages/pigeon/lib/src/swift/swift_generator.dart @@ -1997,7 +1997,7 @@ func deepHash${generatorOptions.fileSpecificClassNameComponent}(value: Any?, has self.api = api } - public func onDeinit(identifier: Int64) { + public func onDeinit(identifier: Int64) throws { api.removeStrongReference(identifier: identifier) { _ in } diff --git a/packages/pigeon/lib/src/swift/templates.dart b/packages/pigeon/lib/src/swift/templates.dart index 35266a2944c..2d1c8c820cf 100644 --- a/packages/pigeon/lib/src/swift/templates.dart +++ b/packages/pigeon/lib/src/swift/templates.dart @@ -28,7 +28,7 @@ String instanceManagerFinalizerDelegateTemplate(InternalSwiftOptions options) => /// Handles the callback when an object is deallocated. protocol ${instanceManagerFinalizerDelegateName(options)}: AnyObject { /// Invoked when the strong reference of an object is deallocated in an `InstanceManager`. - func onDeinit(identifier: Int64) + func onDeinit(identifier: Int64) throws } '''; @@ -66,7 +66,13 @@ internal final class ${_instanceManagerFinalizerName(options)} { } deinit { - delegate?.onDeinit(identifier: identifier) + do { + try delegate?.onDeinit(identifier: identifier) + } catch { + NSLog( + "Failed to call `onDeinit` on object with identifier: \\(identifier)\\n\\(error)\\nStacktrace: \\(Thread.callStackSymbols)" + ) + } } } diff --git a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift index 56de32c5cf1..27fa26db0aa 100644 --- a/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/darwin/test_plugin/Sources/test_plugin/ProxyApiTests.gen.swift @@ -77,7 +77,7 @@ private func nilOrValue(_ value: Any?) -> T? { /// Handles the callback when an object is deallocated. protocol ProxyApiTestsPigeonInternalFinalizerDelegate: AnyObject { /// Invoked when the strong reference of an object is deallocated in an `InstanceManager`. - func onDeinit(identifier: Int64) + func onDeinit(identifier: Int64) throws } // Attaches to an object to receive a callback when the object is deallocated. @@ -113,7 +113,13 @@ internal final class ProxyApiTestsPigeonInternalFinalizer { } deinit { - delegate?.onDeinit(identifier: identifier) + do { + try delegate?.onDeinit(identifier: identifier) + } catch { + NSLog( + "Failed to call `onDeinit` on object with identifier: \(identifier)\n\(error)\nStacktrace: \(Thread.callStackSymbols)" + ) + } } } @@ -428,7 +434,7 @@ open class ProxyApiTestsPigeonProxyApiRegistrar { self.api = api } - public func onDeinit(identifier: Int64) { + public func onDeinit(identifier: Int64) throws { api.removeStrongReference(identifier: identifier) { _ in } diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/InstanceManagerTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/InstanceManagerTests.swift index 716360ed50b..75b4fafafce 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/InstanceManagerTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/InstanceManagerTests.swift @@ -147,6 +147,17 @@ final class InstanceManagerTests: XCTestCase { XCTAssertNil( objc_getAssociatedObject(object!, ProxyApiTestsPigeonInternalFinalizer.associatedObjectKey)) } + + func testExceptionInDeinitDoesNotCauseCrash() { + let finalizerDelegate = ThrowingFinalizerDelegate() + + var object: NSObject? = NSObject() + ProxyApiTestsPigeonInternalFinalizer.attach( + to: object!, identifier: 0, delegate: finalizerDelegate) + + XCTAssertNoThrow(object = nil) + XCTAssertTrue(finalizerDelegate.deinitCalled) + } } class EmptyFinalizerDelegate: ProxyApiTestsPigeonInternalFinalizerDelegate { @@ -160,3 +171,12 @@ class TestFinalizerDelegate: ProxyApiTestsPigeonInternalFinalizerDelegate { lastHandledIdentifier = identifier } } + +class ThrowingFinalizerDelegate: ProxyApiTestsPigeonInternalFinalizerDelegate { + var deinitCalled = false + + func onDeinit(identifier: Int64) throws { + deinitCalled = true + fatalError() + } +} diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 44fa849c60c..6298399391e 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22 -version: 26.1.1 # This must match the version in lib/src/generator_tools.dart +version: 26.1.2 # This must match the version in lib/src/generator_tools.dart environment: sdk: ^3.8.0