Skip to content

vm: avoid stack overflow on recursive accessor calls#4699

Merged
jedel1043 merged 3 commits intoboa-dev:mainfrom
Flamki:fix/getter-setter-recursion-4535
Feb 27, 2026
Merged

vm: avoid stack overflow on recursive accessor calls#4699
jedel1043 merged 3 commits intoboa-dev:mainfrom
Flamki:fix/getter-setter-recursion-4535

Conversation

@Flamki
Copy link
Copy Markdown
Contributor

@Flamki Flamki commented Feb 23, 2026

This Pull Request fixes/closes #4535.

Summary

  • Track nested host-driven VM re-entry (JsObject::call / JsObject::construct) with a new Vm::host_call_depth counter.
  • Include host_call_depth in Context::check_runtime_limits() recursion checks so recursive accessor calls fail with RuntimeLimitError::Recursion instead of overflowing the native stack.
  • Unignore and strengthen the regression test in �m/tests.rs by exercising the async-generator hen getter recursion path with a higher recursion limit.

Notes

  • I could not run cargo in this environment (toolchain not available), so CI is expected to validate formatting, lint, and tests.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 23, 2026

Test262 conformance changes

Test result main count PR count difference
Total 52,862 52,862 0
Passed 49,504 49,504 0
Ignored 2,262 2,262 0
Failed 1,096 1,096 0
Panics 0 0 0
Conformance 93.65% 93.65% 0.00%

@Flamki Flamki force-pushed the fix/getter-setter-recursion-4535 branch from 430081c to 9966682 Compare February 25, 2026 06:48
@Flamki
Copy link
Copy Markdown
Contributor Author

Flamki commented Feb 25, 2026

Follow-up hardening pushed in 9966682.

What I changed:

  • Rebased branch on latest main.
  • Added a dedicated regression test for recursive setters:

ecursion_in_setter_throws_uncatchable_error

  • asserts RuntimeLimitError::Recursion for set x(v) { this.x = v; } recursion.

This complements the existing async-generator getter regression and ensures both accessor call directions are covered by runtime-limit behavior.

@jedel1043
Copy link
Copy Markdown
Member

I'd suggest measuring the performance impact of this change, because keeping track of recursive native calls sounds like it could be detrimental for perf. You can use https://github.com/boa-dev/data/blob/main/bench/bench-v8/combined.js for this.

@Flamki Flamki force-pushed the fix/getter-setter-recursion-4535 branch from 9966682 to 8b867e2 Compare February 27, 2026 13:16
@Flamki Flamki requested a review from a team as a code owner February 27, 2026 13:16
@Flamki
Copy link
Copy Markdown
Contributor Author

Flamki commented Feb 27, 2026

@jedel1043 thanks for raising this, I took a careful pass on perf.

I built clean release binaries for:

  • upstream/main (549d14a5)
  • this branch (390f0a1b, plus the latest test-only commit)

I first tried to run the exact benchmark you suggested from boa-dev/data (bench/bench-v8/combined.js). On my Windows setup, that script stack-overflows on both revisions before producing comparable scores, so I couldn’t get a reliable canonical A/B from it locally.

To still get signal, I ran fallback release A/B hot-path measurements (11 runs each, first run dropped as warmup) focused on accessor/property/function throughput:

Script main mean (ms) branch mean (ms) delta
accessor_hot.js 3894.162 3629.003 -6.81%
plain_prop_hot.js 1446.026 1381.159 -4.49%
func_hot.js 7877.123 7616.737 -3.31%

From this local fallback measurement, I did not observe a regression from host_call_depth tracking.

I also lowered both recursion regression test limits to 128 for platform stability and re-ran:
cargo test -p boa_engine vm::tests -> 26 passed, 0 failed.

Copy link
Copy Markdown
Member

@jedel1043 jedel1043 left a comment

Choose a reason for hiding this comment

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

Thanks!

Maybe in the future we'll finally have coroutines to lift all the inner calls to the main evaluation loop, but in the meantime we need to work around this limitation.

@jedel1043 jedel1043 added A-Bug Something isn't working rust labels Feb 27, 2026
@jedel1043 jedel1043 added this to the v1.0.0 milestone Feb 27, 2026
@jedel1043 jedel1043 enabled auto-merge February 27, 2026 19:18
@jedel1043 jedel1043 added this pull request to the merge queue Feb 27, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 57.12%. Comparing base (6ddc2b4) to head (8b867e2).
⚠️ Report is 694 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4699      +/-   ##
==========================================
+ Coverage   47.24%   57.12%   +9.88%     
==========================================
  Files         476      549      +73     
  Lines       46892    60406   +13514     
==========================================
+ Hits        22154    34507   +12353     
- Misses      24738    25899    +1161     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Merged via the queue into boa-dev:main with commit e6114cf Feb 27, 2026
18 checks passed
akash-R-A-J pushed a commit to akash-R-A-J/boa that referenced this pull request Mar 1, 2026
This Pull Request fixes/closes boa-dev#4535.

## Summary
- Track nested host-driven VM re-entry (JsObject::call /
JsObject::construct) with a new Vm::host_call_depth counter.
- Include host_call_depth in Context::check_runtime_limits() recursion
checks so recursive accessor calls fail with
RuntimeLimitError::Recursion instead of overflowing the native stack.
- Unignore and strengthen the regression test in m/tests.rs by
exercising the async-generator hen getter recursion path with a higher
recursion limit.

## Notes
- I could not run cargo in this environment (toolchain not available),
so CI is expected to validate formatting, lint, and tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Getters and setters can cause stack overflows

2 participants