Skip to content

Check for isolate termination in iterating C++ callbacks#6331

Merged
erikcorry merged 2 commits intomainfrom
erikcorry/iterator-loop
Mar 16, 2026
Merged

Check for isolate termination in iterating C++ callbacks#6331
erikcorry merged 2 commits intomainfrom
erikcorry/iterator-loop

Conversation

@erikcorry
Copy link
Copy Markdown
Contributor

Root cause: When JS code uses Array.from() or spread on a C++ iterator (like the SQL cursor), V8's Torque builtin loops over .next() calls without JS back-edge interrupt checks. If TerminateExecution() is called (e.g. by the near-heap-limit callback when memory is exceeded), the termination request sits unprocessed in the stack guard, and the iterator keeps running, growing the heap until it hits the 4GB pointer compression cage limit and crashes.

Three changes:

  1. deps/workerd/src/workerd/jsg/setup.h -- Added requestTermination() / isTerminationRequested() flag on IsolateBase, checkable from C++ callbacks without relying on V8's internal interrupt processing.

  2. deps/workerd/src/workerd/jsg/iterator.h + iterator.c++ -- nextImpl() checks isTerminationRequested() after each successful row and throws a JS exception if set. V8 sees the exception on the callback return path and stops the iteration.

  3. src/edgeworker/scheduling/limit-enforcer-impl.c++ -- terminate() now calls requestTermination() alongside TerminateExecution().

Bug: EW-10621

@erikcorry erikcorry requested review from a team as code owners March 16, 2026 14:31
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 16, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Mar 16, 2026

error: Your local changes to the following files would be overwritten by checkout:
.opencode/package.json
Please commit your changes or stash them before you switch branches.
Aborting

github run

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Mar 16, 2026

@erikcorry Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

@erikcorry erikcorry force-pushed the erikcorry/iterator-loop branch from 43ca90e to b5e9d6f Compare March 16, 2026 14:38
@erikcorry erikcorry requested a review from dcarney-cf March 16, 2026 14:41
erikcorry and others added 2 commits March 16, 2026 20:37
Root cause: When JS code uses Array.from() or spread on a C++ iterator (like
the SQL cursor), V8's Torque builtin loops over .next() calls without JS
back-edge interrupt checks. If TerminateExecution() is called (e.g. by the
near-heap-limit callback when memory is exceeded), the termination request sits
unprocessed in the stack guard, and the iterator keeps running, growing the
heap until it hits the 4GB pointer compression cage limit and crashes.

Three changes:

1. deps/workerd/src/workerd/jsg/setup.h -- Added requestTermination() /
isTerminationRequested() flag on IsolateBase, checkable from C++ callbacks
without relying on V8's internal interrupt processing.

2. deps/workerd/src/workerd/jsg/iterator.h + iterator.c++ -- nextImpl() checks
isTerminationRequested() after each successful row and throws a JS exception if
set. V8 sees the exception on the callback return path and stops the iteration.

3. src/edgeworker/scheduling/limit-enforcer-impl.c++ -- terminate() now calls
requestTermination() alongside TerminateExecution().

Bug: EW-10621
@erikcorry erikcorry force-pushed the erikcorry/iterator-loop branch from bd280a8 to bcba1b6 Compare March 16, 2026 19:37
@erikcorry erikcorry enabled auto-merge (squash) March 16, 2026 19:48
@erikcorry erikcorry merged commit 7272ada into main Mar 16, 2026
22 checks passed
@erikcorry erikcorry deleted the erikcorry/iterator-loop branch March 16, 2026 20:20
// Signals that execution should be terminated immediately, including during C++ iterator
// callbacks where V8's own TerminateExecution() interrupt would not be checked.
// Also calls V8's TerminateExecution(). See IsolateBase::requestTermination().
void requestTermination();
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.

I think you need to make this method thread-safe. It looks like you've arranged for it to be called from many places where we may be terminating from another thread. So this needs to be const and probably the terminationRequested boolean needs to be an atomic.

(Though don't think there's any problem in practice since it's just a boolean...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants