From b010ac8506aeb1659cb5d6b93ceb1070d91ef7ea Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Mon, 23 Feb 2026 10:34:19 +0100 Subject: [PATCH] fix use-after-free --- Sources/JavaScriptKit/BridgeJSIntrinsics.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 5adccdc0..f76f4de7 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -384,7 +384,12 @@ extension JSObject: _BridgedSwiftStackType { } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Int32 { - return _swift_js_retain(Int32(bitPattern: self.id)) + // withExtendedLifetime is required here to prevent a use-after-free. + // In a `consuming func`, Swift ARC may release `self` (and thus release + // the underlying JS reference) as soon as it extracts `self.id`, which + // happens *before* `_swift_js_retain` is called. `withExtendedLifetime` forces + // `self` to stay alive until after `_swift_js_retain` returns. + return withExtendedLifetime(self) { _swift_js_retain(Int32(bitPattern: self.id)) } } @_spi(BridgeJS) public consuming func bridgeJSStackPush() {