fix: only set Node's WASM streaming callback when fetch is enabled#51953
Conversation
Node.js v24.16.0 removed the experimental_fetch gate around isolate->SetWasmStreamingCallback() (nodejs/node#62759). When fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch was rebased for the version bump, the flag was restored but the gate was not. As a result, Node.js unconditionally overrode Blink's WebAssembly streaming callback in renderer and worker processes, where Electron passes --no-experimental-fetch and skips the bootstrap file that registers Node's JS-side streaming implementation. Any call to WebAssembly.compileStreaming() or instantiateStreaming() in a renderer with nodeIntegration then failed the CHECK(\!impl.IsEmpty()) assertion in node_wasm_web_api.cc and crashed the renderer. Restore the gate so Blink's streaming callback stays in place in processes where Node's fetch is disabled. Fixes #51950
|
Thoughts on #51923, that would also address the broken code path. I am fine with either just want to get consensus on which change to land to address the issue. |
|
This is addressing the callback registered on the isolate, which #51923 doesn't cover yet. Approving as an immediate regression fix. |
|
Release Notes Persisted
|
|
I was unable to backport this PR to "41-x-y" cleanly; |
|
I have automatically backported this PR to "43-x-y", please check out #51955 |
|
I have automatically backported this PR to "42-x-y", please check out #51956 |
…lectron#51953) * fix: only set Node's WASM streaming callback when fetch is enabled Node.js v24.16.0 removed the experimental_fetch gate around isolate->SetWasmStreamingCallback() (nodejs/node#62759). When fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch was rebased for the version bump, the flag was restored but the gate was not. As a result, Node.js unconditionally overrode Blink's WebAssembly streaming callback in renderer and worker processes, where Electron passes --no-experimental-fetch and skips the bootstrap file that registers Node's JS-side streaming implementation. Any call to WebAssembly.compileStreaming() or instantiateStreaming() in a renderer with nodeIntegration then failed the CHECK(\!impl.IsEmpty()) assertion in node_wasm_web_api.cc and crashed the renderer. Restore the gate so Blink's streaming callback stays in place in processes where Node's fetch is disabled. Fixes electron#51950 * test: cover WebAssembly streaming compilation in renderers with nodeIntegration
- Resolve modify/delete on the fetch patch (delete wins; the experimental_fetch gate it added to environment.cc is no longer needed since WasmResponseExtensions::Initialize handles the callback restoration in Electron's renderer code). - Revert the environment.cc index hash in api_delete_deprecated_fields_on_v8_isolate.patch now that the preceding patch is gone (verified with `e patches node`). - Preserve Blink's EventSource around LoadEnvironment in renderer and worker: Node's setupEventsource() in pre_execution.js deletes globalThis.EventSource whenever --experimental-eventsource is not set, and unlike setupNavigator/setupWebStorage it does not check noBrowserGlobals first. The previous blink* stash covered this as a side effect; restore just EventSource explicitly in C++. - Extend the [native code] spec assertion to cover EventSource.
* chore: remove EnvironmentOptions::experimental_fetch dependency Node.js removed the experimental_fetch option in nodejs/node#62759 since fetch is now unconditionally enabled. We had been patching the field back in so that node_main.cc could read it and node_bindings.cc could pass --no-experimental-fetch to renderer/worker processes. Neither is necessary: - In ELECTRON_RUN_AS_NODE mode, fetch is always available, so WASM streaming (which depends on Response) should always be set up. - In renderer/worker processes, kNoBrowserGlobals already causes Node's PrincipalRealm::BootstrapRealm to skip internal/bootstrap/web/exposed-window-or-worker.js, which is where fetch/Request/Response/Headers/FormData are defined. Node's fetch globals were never being installed; Blink's win by default. Drop the patch and the two call sites that depended on it. Closes #51912 * fix: restore Blink's WASM streaming callback in renderer/worker SetIsolateUpForNode now unconditionally registers Node's WASM streaming callback (nodejs/node#62759 dropped the experimental_fetch gate). With kNoBrowserGlobals the JS half of that callback is never installed, so WebAssembly.compileStreaming/instantiateStreaming would crash on CHECK(\!impl.IsEmpty()) in node_wasm_web_api.cc. Re-register Blink's handler via WasmResponseExtensions::Initialize after CreateEnvironment in renderer and worker so Blink's implementation wins. Also drop the now-redundant blink* global stash/restore: with kNoBrowserGlobals Node neither installs nor deletes fetch/Response/etc, so Blink's bindings are never disturbed and the round-trip through blinkfetch was a no-op. Add a spec asserting fetch/Headers/Request/Response/FormData stringify to [native code] in a nodeIntegration renderer. * fixup: rebase on #51953 and preserve Blink's EventSource - Resolve modify/delete on the fetch patch (delete wins; the experimental_fetch gate it added to environment.cc is no longer needed since WasmResponseExtensions::Initialize handles the callback restoration in Electron's renderer code). - Revert the environment.cc index hash in api_delete_deprecated_fields_on_v8_isolate.patch now that the preceding patch is gone (verified with `e patches node`). - Preserve Blink's EventSource around LoadEnvironment in renderer and worker: Node's setupEventsource() in pre_execution.js deletes globalThis.EventSource whenever --experimental-eventsource is not set, and unlike setupNavigator/setupWebStorage it does not check noBrowserGlobals first. The previous blink* stash covered this as a side effect; restore just EventSource explicitly in C++. - Extend the [native code] spec assertion to cover EventSource. * fixup: pass --experimental-eventsource instead of C++ save/restore The C++ save/restore around LoadEnvironment was too late: preload scripts run inside LoadEnvironment, after Node's setupEventsource() has deleted globalThis.EventSource but before the C++ restore. This broke 'preload has synchronous access to all eventual window APIs'. Pass --experimental-eventsource for renderer/worker so Node's setupEventsource() becomes a no-op and Blink's binding is never deleted. Under kNoBrowserGlobals Node never installs its own undici EventSource, so the flag's only effect is suppressing the delete.
* chore: remove EnvironmentOptions::experimental_fetch dependency Node.js removed the experimental_fetch option in nodejs/node#62759 since fetch is now unconditionally enabled. We had been patching the field back in so that node_main.cc could read it and node_bindings.cc could pass --no-experimental-fetch to renderer/worker processes. Neither is necessary: - In ELECTRON_RUN_AS_NODE mode, fetch is always available, so WASM streaming (which depends on Response) should always be set up. - In renderer/worker processes, kNoBrowserGlobals already causes Node's PrincipalRealm::BootstrapRealm to skip internal/bootstrap/web/exposed-window-or-worker.js, which is where fetch/Request/Response/Headers/FormData are defined. Node's fetch globals were never being installed; Blink's win by default. Drop the patch and the two call sites that depended on it. Closes #51912 Co-authored-by: Felix Rieseberg <f@anthropic.com> * fix: restore Blink's WASM streaming callback in renderer/worker SetIsolateUpForNode now unconditionally registers Node's WASM streaming callback (nodejs/node#62759 dropped the experimental_fetch gate). With kNoBrowserGlobals the JS half of that callback is never installed, so WebAssembly.compileStreaming/instantiateStreaming would crash on CHECK(\!impl.IsEmpty()) in node_wasm_web_api.cc. Re-register Blink's handler via WasmResponseExtensions::Initialize after CreateEnvironment in renderer and worker so Blink's implementation wins. Also drop the now-redundant blink* global stash/restore: with kNoBrowserGlobals Node neither installs nor deletes fetch/Response/etc, so Blink's bindings are never disturbed and the round-trip through blinkfetch was a no-op. Add a spec asserting fetch/Headers/Request/Response/FormData stringify to [native code] in a nodeIntegration renderer. Co-authored-by: Felix Rieseberg <f@anthropic.com> * fixup: rebase on #51953 and preserve Blink's EventSource - Resolve modify/delete on the fetch patch (delete wins; the experimental_fetch gate it added to environment.cc is no longer needed since WasmResponseExtensions::Initialize handles the callback restoration in Electron's renderer code). - Revert the environment.cc index hash in api_delete_deprecated_fields_on_v8_isolate.patch now that the preceding patch is gone (verified with `e patches node`). - Preserve Blink's EventSource around LoadEnvironment in renderer and worker: Node's setupEventsource() in pre_execution.js deletes globalThis.EventSource whenever --experimental-eventsource is not set, and unlike setupNavigator/setupWebStorage it does not check noBrowserGlobals first. The previous blink* stash covered this as a side effect; restore just EventSource explicitly in C++. - Extend the [native code] spec assertion to cover EventSource. Co-authored-by: Felix Rieseberg <f@anthropic.com> * fixup: pass --experimental-eventsource instead of C++ save/restore The C++ save/restore around LoadEnvironment was too late: preload scripts run inside LoadEnvironment, after Node's setupEventsource() has deleted globalThis.EventSource but before the C++ restore. This broke 'preload has synchronous access to all eventual window APIs'. Pass --experimental-eventsource for renderer/worker so Node's setupEventsource() becomes a no-op and Blink's binding is never deleted. Under kNoBrowserGlobals Node never installs its own undici EventSource, so the flag's only effect is suppressing the delete. Co-authored-by: Felix Rieseberg <f@anthropic.com> --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Felix Rieseberg <f@anthropic.com>
…tron#51923) * chore: remove EnvironmentOptions::experimental_fetch dependency Node.js removed the experimental_fetch option in nodejs/node#62759 since fetch is now unconditionally enabled. We had been patching the field back in so that node_main.cc could read it and node_bindings.cc could pass --no-experimental-fetch to renderer/worker processes. Neither is necessary: - In ELECTRON_RUN_AS_NODE mode, fetch is always available, so WASM streaming (which depends on Response) should always be set up. - In renderer/worker processes, kNoBrowserGlobals already causes Node's PrincipalRealm::BootstrapRealm to skip internal/bootstrap/web/exposed-window-or-worker.js, which is where fetch/Request/Response/Headers/FormData are defined. Node's fetch globals were never being installed; Blink's win by default. Drop the patch and the two call sites that depended on it. Closes electron#51912 * fix: restore Blink's WASM streaming callback in renderer/worker SetIsolateUpForNode now unconditionally registers Node's WASM streaming callback (nodejs/node#62759 dropped the experimental_fetch gate). With kNoBrowserGlobals the JS half of that callback is never installed, so WebAssembly.compileStreaming/instantiateStreaming would crash on CHECK(\!impl.IsEmpty()) in node_wasm_web_api.cc. Re-register Blink's handler via WasmResponseExtensions::Initialize after CreateEnvironment in renderer and worker so Blink's implementation wins. Also drop the now-redundant blink* global stash/restore: with kNoBrowserGlobals Node neither installs nor deletes fetch/Response/etc, so Blink's bindings are never disturbed and the round-trip through blinkfetch was a no-op. Add a spec asserting fetch/Headers/Request/Response/FormData stringify to [native code] in a nodeIntegration renderer. * fixup: rebase on electron#51953 and preserve Blink's EventSource - Resolve modify/delete on the fetch patch (delete wins; the experimental_fetch gate it added to environment.cc is no longer needed since WasmResponseExtensions::Initialize handles the callback restoration in Electron's renderer code). - Revert the environment.cc index hash in api_delete_deprecated_fields_on_v8_isolate.patch now that the preceding patch is gone (verified with `e patches node`). - Preserve Blink's EventSource around LoadEnvironment in renderer and worker: Node's setupEventsource() in pre_execution.js deletes globalThis.EventSource whenever --experimental-eventsource is not set, and unlike setupNavigator/setupWebStorage it does not check noBrowserGlobals first. The previous blink* stash covered this as a side effect; restore just EventSource explicitly in C++. - Extend the [native code] spec assertion to cover EventSource. * fixup: pass --experimental-eventsource instead of C++ save/restore The C++ save/restore around LoadEnvironment was too late: preload scripts run inside LoadEnvironment, after Node's setupEventsource() has deleted globalThis.EventSource but before the C++ restore. This broke 'preload has synchronous access to all eventual window APIs'. Pass --experimental-eventsource for renderer/worker so Node's setupEventsource() becomes a no-op and Blink's binding is never deleted. Under kNoBrowserGlobals Node never installs its own undici EventSource, so the flag's only effect is suppressing the delete.
|
@mlaurencin has manually backported this PR to "41-x-y", please check out #52240 |
…51953) * fix: only set Node's WASM streaming callback when fetch is enabled Node.js v24.16.0 removed the experimental_fetch gate around isolate->SetWasmStreamingCallback() (nodejs/node#62759). When fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch was rebased for the version bump, the flag was restored but the gate was not. As a result, Node.js unconditionally overrode Blink's WebAssembly streaming callback in renderer and worker processes, where Electron passes --no-experimental-fetch and skips the bootstrap file that registers Node's JS-side streaming implementation. Any call to WebAssembly.compileStreaming() or instantiateStreaming() in a renderer with nodeIntegration then failed the CHECK(\!impl.IsEmpty()) assertion in node_wasm_web_api.cc and crashed the renderer. Restore the gate so Blink's streaming callback stays in place in processes where Node's fetch is disabled. Fixes #51950 * test: cover WebAssembly streaming compilation in renderers with nodeIntegration
#52240) * fix: only set Node's WASM streaming callback when fetch is enabled (#51953) * fix: only set Node's WASM streaming callback when fetch is enabled Node.js v24.16.0 removed the experimental_fetch gate around isolate->SetWasmStreamingCallback() (nodejs/node#62759). When fix_allow_disabling_fetch_in_renderer_and_worker_processes.patch was rebased for the version bump, the flag was restored but the gate was not. As a result, Node.js unconditionally overrode Blink's WebAssembly streaming callback in renderer and worker processes, where Electron passes --no-experimental-fetch and skips the bootstrap file that registers Node's JS-side streaming implementation. Any call to WebAssembly.compileStreaming() or instantiateStreaming() in a renderer with nodeIntegration then failed the CHECK(\!impl.IsEmpty()) assertion in node_wasm_web_api.cc and crashed the renderer. Restore the gate so Blink's streaming callback stays in place in processes where Node's fetch is disabled. Fixes #51950 * test: cover WebAssembly streaming compilation in renderers with nodeIntegration * re-export node patches * update patches --------- Co-authored-by: Samuel Attard <sam@electronjs.org>
Fixes #51950
Description of Change
Node.js v24.16.0 removed the
experimental_fetchgate aroundisolate->SetWasmStreamingCallback()(nodejs/node#62759). Whenfix_allow_disabling_fetch_in_renderer_and_worker_processes.patchwas rebased for the Node bump, the flag was restored but that gate was not.As a result, Node.js unconditionally overrode Blink's WebAssembly streaming callback in renderer and worker processes — where we pass
--no-experimental-fetchand never register Node's JS-side streaming implementation. AnyWebAssembly.compileStreaming()/instantiateStreaming()call in a renderer withnodeIntegration: truethen failed theCHECK(!impl.IsEmpty())assertion innode_wasm_web_api.ccand crashed the renderer.This restores the gate (matching the v24.15.0 behavior) so Blink's streaming callback stays installed in processes where Node's fetch is disabled, and adds a regression test. Browser, utility, and
ELECTRON_RUN_AS_NODEprocesses are unaffected — fetch is enabled there, so Node's streaming implementation is still installed.Checklist
npm testpassesRelease Notes
Notes: Fixed a renderer crash when calling
WebAssembly.compileStreaming()orWebAssembly.instantiateStreaming()withnodeIntegrationenabled.