Skip to content

fix:stack-overflow due to unbounded recursion in structuredClone() - #5661

Open
Skyu2231 wants to merge 1 commit into
boa-dev:mainfrom
Skyu2231:fix/stack-overflow(issue-5653)
Open

Skyu2231 wants to merge 1 commit into
boa-dev:mainfrom
Skyu2231:fix/stack-overflow(issue-5653)

Conversation

@Skyu2231

@Skyu2231 Skyu2231 commented Nov 12, 2026 •

Copy link
Copy Markdown

Fixes #5653

It changes the following:

  • prevents the aborting of code for larger nested chains.
  • engine still works after error is thrown
  • passes all 10 tests including new depth.js which covers test regarding stack-overflow.

Extras added to the codebase:

  • MAX_CLONE_DEPTH variable which basically tracks the upper bound of stack and prevents overflowing.
  • depth_limit_exceeded() which returns error if the object is deeply nested using the same js_error! convention as unsupported_type()

How it works:

-> boa/core/wintertc/src/store/from.rs (serialization)

  • SeenMap now maintains a depth counter along with the existing address map.
  • try_from_js_value checks whether the depth limit has been reached. If not, it increments the counter, calls the renamed try_from_js_value_inner, and then decrements the counter after the operation finishes, even if an error occurs.
  • All recursive container operations, including arrays (line 102), typed arrays (line 148), Map (lines 196–197), Set (line 223), and object fields (line 287), go through try_from_js_value. This means a single check at this function controls the recursion depth for the entire serialization process.

-> boa/core/wintertc/src/store/to.rs (deserialization)

  • ReverseSeenMap now also maintains a depth counter.
  • try_value_into_js follows the same approach: it checks the depth limit, increments the counter, calls try_value_into_js_inner, and then decrements the counter, including when an error occurs.
  • This ensures that recursive operations involving object fields, arrays, typed arrays, Map, Set, and DataView are all covered by the same depth check during deserialization.

-> boa/core/runtime/tests/clone/depth.js (new regression test)

  • Verifies that cloning 100-level object and array chains works correctly.
  • Verifies that cloning 300-level and 10,000-level chains throws a catchable error instead of aborting the process.
  • Confirms that the engine continues to work normally after the error is thrown.
  • Also confirms that the existing cycle behavior remains unchanged.

@Skyu2231
Skyu2231 requested a review from a team as a code owner November 12, 2026 14:10
@github-actions github-actions Bot added C-Tests Issues and PRs related to the tests. C-Javascript Pull requests that update Javascript code C-Runtime Issues and PRs related to Boa's runtime features Waiting On Review Waiting on reviews from the maintainers labels Nov 12, 2026
@github-actions github-actions Bot added this to the v0.23 milestone Nov 12, 2026

This branch has not been deployed

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

Labels

C-Javascript Pull requests that update Javascript code C-Runtime Issues and PRs related to Boa's runtime features C-Tests Issues and PRs related to the tests. Waiting On Review Waiting on reviews from the maintainers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbounded Native Recursion in structuredClone() Serialization/Deserialization Causes Stack Overflow

1 participant