Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog.d/6762-parity-fork-containment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Fixed

- Contain recursively re-executing cluster tests inside a per-test process
budget and reap their orphaned workers, preventing the Node parity suite
from exhausting the runner's process limit.
4 changes: 1 addition & 3 deletions crates/perry-codegen/src/loop_purity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@ fn expr_alloc_free(e: &Expr) -> bool {
// Element READS never allocate — they return an existing element / a
// number. Recurse so the object and index are themselves alloc-free.
Expr::IndexGet { object, index } => expr_alloc_free(object) && expr_alloc_free(index),
Expr::BufferIndexGet { buffer, index } => {
expr_alloc_free(buffer) && expr_alloc_free(index)
}
Expr::BufferIndexGet { buffer, index } => expr_alloc_free(buffer) && expr_alloc_free(index),
Expr::Uint8ArrayGet { array, index } => expr_alloc_free(array) && expr_alloc_free(index),
// `arr[i]++` / `--`: read-modify-write of an existing numeric slot, no
// growth, no allocation.
Expand Down
40 changes: 39 additions & 1 deletion run_parity_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -772,8 +772,46 @@ for test_file in "${TEST_FILES[@]}"; do
# up on the 2>&1-captured stream for any test that exercises a flagged
# API (dns/dgram loopback, v8 heap snapshot, …) and diff against Node.
perry_tmp=$(mktemp)
run_with_timeout 10 env PERRY_STUB_DIAG=off "${parity_env[@]}" "$perry_binary" "${test_argv[@]}" > "$perry_tmp" 2>&1
# Cap the test binary's fork budget at current-user-tasks + 50: legit
# multi-process tests (cluster/child_process) fit easily, while a
# fork-bombing test (cluster re-exec loop, 2026-07-22) stalls at ~50
# orphans instead of saturating the user process limit — which would
# starve the harness itself out of fork() and kill the whole run.
# If the proc count can't be measured or the cap can't be applied, abort
# this test before exec: an uncapped run could recreate the fork bomb this
# containment layer exists to prevent. The budget is per-UID, not per-tree,
# so a concurrent heavy job can transiently eat the +50 headroom; recomputing
# per test keeps that window small, and the worst case is one test
# classified as crash rather than a wedged machine.
run_with_timeout 10 "$BASH" -c '
if [ "$(uname -s)" = "Linux" ]; then
proc_list=$(ps -u "$(id -u)" -L -o lwp= 2>/dev/null)
else
proc_list=$(ps -u "$(id -u)" -o pid= 2>/dev/null)
fi || {
echo "failed to measure the current user process count" >&2
exit 125
}
nproc_now=$(printf "%s\n" "$proc_list" | awk "NF { count++ } END { print count + 0 }") || {
echo "failed to count the current user processes" >&2
exit 125
}
if ! [ "$nproc_now" -gt 0 ] 2>/dev/null; then
echo "invalid current user process count: $nproc_now" >&2
exit 125
fi
if ! ulimit -u $(( nproc_now + 50 )) 2>/dev/null; then
echo "failed to apply the per-test process limit" >&2
exit 125
fi
exec "$@"' _ env PERRY_STUB_DIAG=off "${parity_env[@]}" "$perry_binary" "${test_argv[@]}" > "$perry_tmp" 2>&1
perry_exit=$?
# Reap orphaned children of the test binary (cluster tests fork workers
# that survive the timeout kill of the direct child and can fork-bomb the
# machine — 2026-07-22). Scoped to this run's tmp dir, so concurrent
# suite runs are unaffected. pkill -f treats the pattern as a regex, so
# escape the path's metacharacters (the mktemp dir contains a dot).
pkill -9 -f "$(printf '%s/' "$PARITY_TMP" | sed 's/[][\.*^$()+?{|]/\\&/g')" 2>/dev/null
perry_output=$(cap_output < "$perry_tmp")
rm -f "$perry_tmp"

Expand Down
7 changes: 7 additions & 0 deletions test-parity/gap_snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@
"category": "gap-categorical",
"reason": "node --experimental-strip-types refuses this file: ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX, 'TypeScript parameter property is not supported in strip-only mode'. The oracle CANNOT execute the very feature under test, so this has never verified anything. Fix by giving it a test-parity/expected/<name>.txt fixture (expected-output mode), not by editing the test."
},
"test_gap_enum_in_function_body": {
"status": "node_fail",
"issue": null,
"added": "2026-07-30",
"category": "gap-categorical",
"reason": "node --experimental-strip-types refuses a function-body enum with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX. The oracle cannot execute the TypeScript syntax under test; add an expected-output fixture to restore coverage."
},
"test_gap_fetch_instanceof_5433": {
"status": "crash",
"issue": "5433",
Expand Down
Loading