Conversation
|
Review requested:
|
|
Welcome to Node.js, and thank you for your first contribution! Before review, please take a moment to read:
Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal. |
`node_napi_env__::New()` returns nullptr after throwing when an add-on declares a Node-API version this binary does not support, but `napi_module_register_by_symbol()` dereferenced the result without checking it. Loading such an add-on segfaulted instead of surfacing the error the version check had already produced, so `require()` could not catch it. Reproduced on v20.x, v22.x, v24.x and v26.8.2 with a ten-line add-on whose only distinguishing content is a NAPI_VERSION above NODE_API_SUPPORTED_VERSION_MAX. `main`, `v22.x-staging` and `v24.x-staging` all lack the check. The error path had no test coverage: the message text appears in exactly one file in the repository, `src/node_api.cc`. A test is added next to `test_null_init`, which covers the sibling early return in the same function. Prepared with assistance from a closed-source coding agent, named in the pull request description. The design, review and validation are my own: I verified the fix and the test against a local build, including removing the four added lines and relinking to confirm the test fails without them. Refs: nodejs#57233 Signed-off-by: Alexey Karimov <krassx@gmail.com>
614013e to
089103e
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #66019 +/- ##
==========================================
- Coverage 90.22% 90.21% -0.01%
==========================================
Files 785 785
Lines 269357 269369 +12
Branches 51511 51507 -4
==========================================
- Hits 243016 243010 -6
- Misses 16853 16882 +29
+ Partials 9488 9477 -11
🚀 New features to boost your workflow:
|
| #include <node_api.h> | ||
|
|
||
| // This add-on declares a Node-API version that no build supports, so loading it | ||
| // must fail with the error `node_napi_env__::New()` throws -- not a crash. |
There was a problem hiding this comment.
Please refrain from commenting impl internals in tests.
| // must fail with the error `node_napi_env__::New()` throws -- not a crash. | |
| // must fail with an error -- not a crash. |
|
|
||
| // An add-on that requires a newer Node-API version than this binary supports | ||
| // must be rejected with an error that `require()` can catch. The version check | ||
| // in `node_napi_env__::New()` already produces that error, but its nullptr |
There was a problem hiding this comment.
Ditto, please refrain from including impl internals in the test comments.
| // `New()` returns nullptr after throwing when the add-on requires a | ||
| // Node-API version this binary does not support. Returning here lets that | ||
| // error surface; dereferencing `env` instead turns it into a segfault. |
There was a problem hiding this comment.
Please avoid explain what the code already literally explained.
| // `New()` returns nullptr after throwing when the add-on requires a | |
| // Node-API version this binary does not support. Returning here lets that | |
| // error surface; dereferencing `env` instead turns it into a segfault. | |
| // `module_api_version` is not supported. |
Problem
node_napi_env__::New()validates the Node-API version an add-on declares. Whenthe add-on requires a version this binary does not support, it throws a
descriptive error and returns
nullptr:napi_module_register_by_symbol()then dereferences thatnullptrwithoutchecking it:
So loading such an add-on segfaults, and the error Node already built — "…
requires Node-API version N, but this version of Node.js only supports version M
add-ons." — is never delivered.
require()cannot catch it, because the processis gone.
Reproduction
A ten-line add-on, no third-party tooling, plain
node-gyp:Confirmed on v20.x, v22.x, v24.x and v26.8.2, and
main,v22.x-stagingandv24.x-stagingall still lack the check.Fix
Return when
New()returnsnullptr; the error it threw then propagatesnormally. Verified against a local build of this branch:
Removing the four added lines and relinking the same tree turns that back into
exit=139with thecatchnever reached, so the new test fails without the fixand passes with it.
node-apiandjs-native-apiboth run clean on the patched build: 102 tests,0 failures.
Test
The error path had no coverage at all —
"requires Node-API version"appears inexactly one file in the repository,
src/node_api.cc, which is how it could beunreachable without anyone noticing. The new test is modelled on
test/node-api/test_null_init, which covers the sibling early return in the samefunction.
Notes for reviewers
This is not a reprise of the Node-API versioning discussion in #57233. That
issue was closed on the grounds that the add-on had been miscompiled by a
third-party tool, which is fair — but it leaves the crash in place. The version
policy is not in question here; only that a check which already detects the
problem and writes an error should be able to deliver it. The reproduction above
involves no external tooling.
#63740 reports a superficially similar segfault in
napi_register_module_v1froma
libnode.soABI mismatch. That is a different root cause and this change doesnot address it.
Closest precedent: #58459 added
CHECK_NOT_NULL(node_env)to this same functionfor the
node::Environmentpointer. This change covers thenapi_envreturnedby
New()twelve lines below, which is the one that is nullable by design.Refs: #57233
AI use disclosure
Per doc/contributing/ai-guidelines.md:
this change was prepared with assistance from Claude Code. The commit
message refers to it only as "a closed-source coding agent", following the
guidance in Naming AI tools in disclosures to keep commercial brand names out
of the commit log and name them here instead.
The design, review and validation are my own. Specifically, what I verified
personally rather than taking on trust:
src/node_api.cc—node_napi_env__::New()returns
nullptron the version-mismatch branch, andnapi_module_register_by_symbol()dereferences it with no check. Confirmedunder a debugger: the faulting register holds 0.
intended error reach a
try/catcharoundrequire().same tree, and confirmed the test fails there (
exit=139, thecatchneverreached) and passes with them. A test that cannot fail would not be worth
adding.
incidental shape: it matches the error text the version check produces, with
the supported-version number left as
\d+so it does not need updating eachtime
NODE_API_SUPPORTED_VERSION_MAXmoves.node-apiandjs-native-apirun clean on the patchedbuild, 102 tests, 0 failures.
I can explain and defend the change during review, and will respond to feedback
myself.