build: delay-load node.exe imports so addons work in any Node-API host on Windows - #83
Open
hexbinoct wants to merge 1 commit into
Open
build: delay-load node.exe imports so addons work in any Node-API host on Windows#83hexbinoct wants to merge 1 commit into
hexbinoct wants to merge 1 commit into
Conversation
The MSVC-built addons bind their napi_* imports to a module literally named NODE.EXE, so only a host process named node.exe can load them. Delay-load those imports and resolve them to the current process image with a delay-load hook, the same approach node-gyp uses, so any Node-API host executable can load the addons regardless of its name. Signed-off-by: hexbinoct <abubakarm@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Windows the test addons are linked against an import library generated from the
.deffiles, whose module name isNODE.EXE. Every.nodefile therefore carries animport table that binds the
napi_*symbols to a module literally namedNODE.EXE.That works when the host process is
node.exe, but any Node-API runtime with adifferent executable name cannot load the addons at all: the loader has no module
named
NODE.EXEto resolve against. In my testing,process.dlopenof a CTS addonmakes Bun 1.3.14 panic with a segfault and makes Deno 2.9.5 crash with 0xC0000005.
The only workaround was renaming the runtime's exe to
node.exe, which is notsomething a conformance suite should require. Linux and macOS are unaffected because
their loaders resolve undefined symbols against the host executable directly.
This is the same problem node-gyp solved years ago, and this PR applies the same
standard fix: the
node.exeimports become delay-loaded (/DELAYLOAD:NODE.EXEplusdelayimp.lib), and a small delay-load hook (src/win_delay_load_hook.cc, modeled onnode-gyp's
win_delay_load_hook.cc) resolves thenode.exemodule to the currentprocess image via
GetModuleHandle(NULL)at runtime, whatever the executable iscalled. The hook also prefers
libnode.dllwhen present, matching node-gyp, so ashared-library Node build works too. The hook and flags are added inside
add_node_api_cts_addonunderif(MSVC), so every addon target gets them andnon-Windows builds are untouched.
Verified on Windows 11 with VS 2022:
js-native-api/2_function_arguments/test.jsunderbun.exe(1.3.14) panics in
process.dlopen(crash report namesNODE.EXE), and underdeno.exe(2.9.5) segfaults with 0xC0000005. Node passes.bun.exeanddeno.exerunning undertheir own names, no rename. A deliberate failing assertion added to the test makes
both exit non-zero, so the addon code is genuinely executing.
npm run node:teststill passes 48/48.produced before: bun 40 pass / 7 fail / 1 timeout, deno 32 pass / 14 fail / 2
crashes, with the same per-test verdicts. The remaining failures are runtime
conformance and harness-portability issues unrelated to this change.
node:26-bookworm, GCC) plusnpm run node:testandnpm run lintall pass on this branch.One behavior note: with delay-loading, an addon that references a symbol the host
does not export now fails when the symbol is first called rather than at load time.
For Node itself nothing changes, since all suite symbols come from the
.deffilesthat Node exports.
Claude found this, wrote the fix, ran the verification, and drafted this text;
I reviewed both the fix and the text.