fix(runtime): green perry-runtime --lib suite on Windows (#7356) - #7419
Merged
Conversation
added 2 commits
August 5, 2026 07:51
Two production bugs and four platform-shape test fixes; the suite goes from three process-killing stoppers to 1635/1635 single-threaded. - js_throw's longjmp was UB on windows-msvc: MSVC longjmp performs a real RtlUnwindEx when _JUMP_BUFFER.Frame (first 8 bytes) is nonzero, and the one-arg setjmp extern leaves that slot as garbage RDX (the CRT _setjmp stores its SECOND parameter there). Measured STATUS_BAD_STACK (0xC0000028) in a compiled probe and _report_gsfailure aborts under the panic=unwind test harness. Zero the slot before jumping: the non-unwinding POSIX semantics are exactly what the savepoint restores assume. A/B: probe (throwing .then / Array.from mapper / Promise.all member / 1000-throw churn) crashes 0xC0000028 without the fix, is byte-identical to the Node oracle with it. - The conservative-scan register snapshot buffer ([u64; 32], 8-aligned) and the ffi::setjmp test buffers violated MSVC _setjmp's 16-byte alignment contract (aligned XMM stores) - an AV whenever the stack lands 8-mod-16. All are repr(align(16)) now; the extern documents both MSVC contracts. - date: TZ-isolation child uses PST8PDT on Windows (UCRT TZ parser silently degrades IANA ids to UTC, failing the subject-is-live guard). - gc malloc-trim test: count that budgeted reclaim REACHED the trim call (the #6180 subject) instead of counting only the glibc/macOS executing arms, which made the gate unsatisfiable where trim is unsupported. - child_process: spawnSync test spawns `cmd /c echo hi` on Windows (echo is a cmd builtin; ENOENT under Node too). - CI: windows-build now runs RUST_TEST_THREADS=1 cargo test --profile perry-dev --lib -p perry-runtime - the arm that keeps the suite from rotting back to unmeasurable. Closes #7356
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThe PR enables Windows ChangesWindows runtime suite
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: Suggested reviewers: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Audit follow-up on this PR. Moving the malloc-trim counter to the top of run_malloc_trim made the gate satisfiable on Windows/musl -- correct, and #6180's subject really is "did budgeted reclaim REACH the trim call", since the bug was ordinary_budgeted skipping it. But it also dropped the stronger property on glibc/macOS. The portable counter witnesses only reaching, so it would pass with the platform arm deleted, while the assertion still read "must invoke allocator trim". Split into two counters: the portable ..._CALLS for "reached", and a cfg-gated ..._EXECUTED incremented inside BOTH the glibc and Darwin arms for "a trim primitive ran". Instrumenting only glibc would have made the macOS gate impossible to satisfy -- the same shape as #7414, where an assertion could not pass because its input was never produced. Verified the new assertion can fail: removing the Darwin instrumentation fails with "on a target with a trim primitive, budgeted reclaim must EXECUTE it".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7356.
#7355 made perry-runtime compile on Windows; running the suite then surfaced the pre-existing failures inventoried in #7356. This lands the fixes and the CI arm that keeps them fixed.
cargo test -p perry-runtime --lib -- --test-threads=1on Windows 11: 1635 passed, 0 failed (previously three process-killing stoppers truncated every run).Production bugs (not test bugs)
js_throw''slongjmpwas undefined behavior on windows-msvc (exception.rs). MSVC''slongjmpreads_JUMP_BUFFER.Frame(the jmp_buf''s first 8 bytes) and, when nonzero, performs a REALRtlUnwindExstack unwind - and our one-argsetjmpextern leaves that slot holding garbage (the CRT_setjmpstores its second parameter there; we pass one). Measured: STATUS_BAD_STACK (0xC0000028) in a release probe; GS-cookie aborts (_report_gsfailure) under the panic=unwind test harness - thedyn_eval/native_abistoppers. Every Rust-side boundary-trap catch on Windows (microtask pump,js_call_catching, iterator trampolines, promise combinators) rode this path in shipped binaries. Fix: zero the Frame slot before the jump, forcing the non-unwinding POSIX-stylelongjmpwhose skipped-cleanup semantics the savepoint restores injs_throwalready assume.A/B with a compiled probe (throwing
.then,Array.frommapper,Promise.allmember, 1000-iteration throw/catch churn), fresh runtime archives both arms,PERRY_RUNTIME_DIRpinned, archive mtimes verified:The conservative-scan register snapshot buffer was under-aligned (
gc/roots.rs). MSVC''s_setjmpsaves XMM registers with aligned stores; the[u64; 32]buffer is 8-aligned - an immediate AV whenever the stack lands 8-mod-16 (measured; same root cause as theffi::setjmpsmoke-test AV that killed the harness). Snapshot + test buffers are nowrepr(align(16)); the extern''s docs record both MSVC contracts.Test-shape fixes (subject kept live on Windows, not skipped)
date: TZ-isolation child usesTZ=PST8PDTon Windows - the UCRT''sTZparser silently degrades IANA ids to UTC, which failed the test''s own subject-is-live guard.gcmalloc-trim: the counter now records that budgeted reclaim reached the trim call (the [gc] Graduate incremental collection: budgeted scanner coverage, assists for all phases, default-on (successor to #6083) #6180 subject - the old bug was skipping it) rather than counting only the glibc/macOS executing arms, which made the gate unsatisfiable on platforms with no trim primitive.child_process:spawnSyncresult-shape test spawnscmd /c echo hion Windows (echois a cmd builtin; ENOENT under Node too).CI
windows-buildnow runsRUST_TEST_THREADS=1 cargo test --profile perry-dev --lib -p perry-runtime- the same single-threaded invocation as the ubuntu leg (#1444), perry-dev profile so it shares the job''s build artifacts instead of paying a second cold build. Verified green locally under exactly that profile/invocation. Note it lands in an existing required job - if the runner budget gets tight the step can be split out, but the local run is ~4s of test time on top of the compile.Out of scope, recorded for honesty
Parallel-mode (
cargo testwith default threads) has 5 pre-existing failures (closure::dynamic_propsx2,gc::tests::teardown,object::prop_plan,global_this_webassembly) - cross-thread interference that CI already sidesteps on every platform by running single-threaded. Windows-latest runner cost: the new step adds one lib-test compile of perry-runtime under perry-dev (shares all dependency rlibs with the build step above).No version bump per external-contributor flow - maintainer bumps at merge. Changelog fragment follows once the PR number exists.
Summary by CodeRabbit
Bug Fixes
Tests
Documentation