Skip to content

src: handle empty MaybeLocal in cjs_lexer::Parse#63885

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
anonrig:fix-cjs-lexer-tolocalchecked
Jun 15, 2026
Merged

src: handle empty MaybeLocal in cjs_lexer::Parse#63885
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
anonrig:fix-cjs-lexer-tolocalchecked

Conversation

@anonrig

@anonrig anonrig commented Jun 13, 2026

Copy link
Copy Markdown
Member

CreateString() and Parse() in src/node_cjs_lexer.cc unconditionally called ToLocalChecked() on the results of String::NewFromOneByte(), String::NewFromUtf8() and Set::Add(). If string or handle allocation fails or an exception is pending on the isolate, these return an empty MaybeLocal and ToLocalChecked() aborts the whole process:

FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal
 1: node::OnFatalError(char const*, char const*)
 3: node::cjs_lexer::Parse(v8::FunctionCallbackInfo<v8::Value> const&)

Parse() is on the hot path of every ESM import of a CJS module (cjsPreparseModuleExports in lib/internal/modules/esm/translators.js), which sits on a normal JS frame and can handle a thrown exception. This change makes CreateString() return MaybeLocal<String> and propagates failure from Parse() as a regular pending JavaScript exception, so an allocation failure surfaces as a recoverable module load error instead of a fatal abort. This matches the failure behavior of the previous WASM-based cjs-module-lexer and the MaybeLocal handling conventions used elsewhere in src/ (e.g. AsArray in src/util-inl.h).

No regression test: the failure requires V8 string/handle allocation to fail inside the binding (export names are bounded by source length, and Set::Add on a fresh Set runs no user code), which cannot be triggered deterministically from JS. Verified locally that test/es-module passes and that the stress reproducer from the issue runs clean.

Fixes: #63323
Refs: #61456

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Jun 13, 2026
@richardlau richardlau added the lts-watch-v24.x PRs that may need to be released in v24.x label Jun 13, 2026
CreateString() and Parse() in node_cjs_lexer.cc unconditionally called
ToLocalChecked() on the results of String::NewFromOneByte(),
String::NewFromUtf8() and Set::Add(). If string or handle allocation
fails or an exception is pending on the isolate, these return an empty
MaybeLocal and ToLocalChecked() aborts the process with
"FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal".

Since Parse() is on the hot path of every ESM import of a CJS module
(cjsPreparseModuleExports), propagate the failure as a regular pending
JavaScript exception instead so callers can recover.

Fixes: nodejs#63323
Refs: nodejs#61456
Signed-off-by: Yagiz Nizipli <[email protected]>
@anonrig
anonrig force-pushed the fix-cjs-lexer-tolocalchecked branch from a2d3572 to 5990609 Compare June 13, 2026 16:48
@anonrig anonrig added the request-ci Add this label to start a Jenkins CI on a PR. label Jun 13, 2026
mcollina

This comment was marked as off-topic.

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@anonrig anonrig added the commit-queue Add this label to land a pull request using GitHub Actions. label Jun 13, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Jun 13, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Jun 15, 2026
@nodejs-github-bot
nodejs-github-bot merged commit aa25a0a into nodejs:main Jun 15, 2026
69 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in aa25a0a

aduh95 pushed a commit that referenced this pull request Jun 18, 2026
CreateString() and Parse() in node_cjs_lexer.cc unconditionally called
ToLocalChecked() on the results of String::NewFromOneByte(),
String::NewFromUtf8() and Set::Add(). If string or handle allocation
fails or an exception is pending on the isolate, these return an empty
MaybeLocal and ToLocalChecked() aborts the process with
"FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal".

Since Parse() is on the hot path of every ESM import of a CJS module
(cjsPreparseModuleExports), propagate the failure as a regular pending
JavaScript exception instead so callers can recover.

Fixes: #63323
Refs: #61456
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: #63885
Reviewed-By: Filip Skokan <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: René <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
nodejs-github-bot pushed a commit that referenced this pull request Jun 20, 2026
Follow-up to aa25a0a. When an export or re-export name cannot be
converted to a V8 string (e.g. on string allocation failure), omit that
individual name and continue instead of bailing out of the whole
preparse. A single pathological name no longer fails the module's
exports preparse; the remaining names are still returned.

Refs: #63885
Refs: #63323
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: #63943
Reviewed-By: Daijiro Wachi <[email protected]>
Reviewed-By: Filip Skokan <[email protected]>
aduh95 pushed a commit that referenced this pull request Jun 20, 2026
Follow-up to aa25a0a. When an export or re-export name cannot be
converted to a V8 string (e.g. on string allocation failure), omit that
individual name and continue instead of bailing out of the whole
preparse. A single pathological name no longer fails the module's
exports preparse; the remaining names are still returned.

Refs: #63885
Refs: #63323
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: #63943
Reviewed-By: Daijiro Wachi <[email protected]>
Reviewed-By: Filip Skokan <[email protected]>
luanmuniz pushed a commit to luanmuniz/node that referenced this pull request Jun 25, 2026
CreateString() and Parse() in node_cjs_lexer.cc unconditionally called
ToLocalChecked() on the results of String::NewFromOneByte(),
String::NewFromUtf8() and Set::Add(). If string or handle allocation
fails or an exception is pending on the isolate, these return an empty
MaybeLocal and ToLocalChecked() aborts the process with
"FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal".

Since Parse() is on the hot path of every ESM import of a CJS module
(cjsPreparseModuleExports), propagate the failure as a regular pending
JavaScript exception instead so callers can recover.

Fixes: nodejs#63323
Refs: nodejs#61456
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: nodejs#63885
Reviewed-By: Filip Skokan <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: René <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
luanmuniz pushed a commit to luanmuniz/node that referenced this pull request Jun 25, 2026
Follow-up to aa25a0a. When an export or re-export name cannot be
converted to a V8 string (e.g. on string allocation failure), omit that
individual name and continue instead of bailing out of the whole
preparse. A single pathological name no longer fails the module's
exports preparse; the remaining names are still returned.

Refs: nodejs#63885
Refs: nodejs#63323
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: nodejs#63943
Reviewed-By: Daijiro Wachi <[email protected]>
Reviewed-By: Filip Skokan <[email protected]>
aduh95 pushed a commit that referenced this pull request Jun 25, 2026
CreateString() and Parse() in node_cjs_lexer.cc unconditionally called
ToLocalChecked() on the results of String::NewFromOneByte(),
String::NewFromUtf8() and Set::Add(). If string or handle allocation
fails or an exception is pending on the isolate, these return an empty
MaybeLocal and ToLocalChecked() aborts the process with
"FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal".

Since Parse() is on the hot path of every ESM import of a CJS module
(cjsPreparseModuleExports), propagate the failure as a regular pending
JavaScript exception instead so callers can recover.

Fixes: #63323
Refs: #61456
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: #63885
Reviewed-By: Filip Skokan <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: René <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
aduh95 pushed a commit that referenced this pull request Jun 25, 2026
Follow-up to aa25a0a. When an export or re-export name cannot be
converted to a V8 string (e.g. on string allocation failure), omit that
individual name and continue instead of bailing out of the whole
preparse. A single pathological name no longer fails the module's
exports preparse; the remaining names are still returned.

Refs: #63885
Refs: #63323
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: #63943
Reviewed-By: Daijiro Wachi <[email protected]>
Reviewed-By: Filip Skokan <[email protected]>
aduh95 pushed a commit that referenced this pull request Jul 21, 2026
Follow-up to aa25a0a. When an export or re-export name cannot be
converted to a V8 string (e.g. on string allocation failure), omit that
individual name and continue instead of bailing out of the whole
preparse. A single pathological name no longer fails the module's
exports preparse; the remaining names are still returned.

Refs: #63885
Refs: #63323
Signed-off-by: Yagiz Nizipli <[email protected]>
PR-URL: #63943
Reviewed-By: Daijiro Wachi <[email protected]>
Reviewed-By: Filip Skokan <[email protected]>
@aduh95 aduh95 removed the lts-watch-v24.x PRs that may need to be released in v24.x label Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash in cjs_lexer::Parse since v24.14.0: FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal

8 participants