Problem Description
Two process-lifecycle tests fail on some hosts because they check whether a process is still alive with a bare PID check, which cannot distinguish a live process from a terminated-but-unreaped one (a zombie).
proc_lifecycle::tests::tree_stop_waits_for_descendants
proc_lifecycle::tests::tree_forced_kill_reaches_sigterm_ignoring_descendant
Both assert on crate::process_is_running(grandchild), which is kill(pid, 0). That call succeeds for a zombie, so a descendant that was terminated correctly still reads as running until the host gets round to reaping it. Whether the test passes therefore depends on reaping latency, which varies by environment — it passes on the CI runners and fails reliably under WSL2.
The product code is correct; only the tests are wrong. identity_state deliberately treats a zombie as gone via process_has_exited (crates/rocm-core/src/proc_lifecycle.rs:325-332, matching state Z), and terminate_verified uses that logic throughout. The tests bypass it and use the weaker check instead.
Steps to Reproduce
Run cargo test -p rocm-core proc_lifecycle on a host that reaps orphans slowly (WSL2 reproduces it every time):
thread 'proc_lifecycle::tests::tree_stop_waits_for_descendants' panicked at
crates/rocm-core/src/proc_lifecycle.rs:546:9:
Tree stop must terminate the descendant, not just the root
Instrumenting the same scenario shows the termination worked and only the assertion is wrong:
PROBE root=67962 grandchild=67963 tree=[67962, 67963]
PROBE after_term grandchild_running=true
PROBE grandchild_proc_state=Z
PROBE grandchild_identity_state=Gone
The tree was enumerated correctly, both processes were signalled, the descendant is a zombie (Z), and the product's own identity_state correctly reports Gone. Only the bare PID check disagrees.
Impact
Beyond the two failing tests, this blocks the pre-push hook (which runs the test suite) for anyone developing on an affected host, so pushes require --no-verify — which also skips the signing and sign-off checks that hook enforces.
Suggested Fix
Assert through the same semantics the product uses: capture a ProcessIdentity for the descendant before the stop and check is_exited(identity_state(&grandchild)) afterwards. A regression test pinning the zombie semantics would stop the weaker check from creeping back in.
Problem Description
Two process-lifecycle tests fail on some hosts because they check whether a process is still alive with a bare PID check, which cannot distinguish a live process from a terminated-but-unreaped one (a zombie).
proc_lifecycle::tests::tree_stop_waits_for_descendantsproc_lifecycle::tests::tree_forced_kill_reaches_sigterm_ignoring_descendantBoth assert on
crate::process_is_running(grandchild), which iskill(pid, 0). That call succeeds for a zombie, so a descendant that was terminated correctly still reads as running until the host gets round to reaping it. Whether the test passes therefore depends on reaping latency, which varies by environment — it passes on the CI runners and fails reliably under WSL2.The product code is correct; only the tests are wrong.
identity_statedeliberately treats a zombie as gone viaprocess_has_exited(crates/rocm-core/src/proc_lifecycle.rs:325-332, matching stateZ), andterminate_verifieduses that logic throughout. The tests bypass it and use the weaker check instead.Steps to Reproduce
Run
cargo test -p rocm-core proc_lifecycleon a host that reaps orphans slowly (WSL2 reproduces it every time):Instrumenting the same scenario shows the termination worked and only the assertion is wrong:
The tree was enumerated correctly, both processes were signalled, the descendant is a zombie (
Z), and the product's ownidentity_statecorrectly reportsGone. Only the bare PID check disagrees.Impact
Beyond the two failing tests, this blocks the
pre-pushhook (which runs the test suite) for anyone developing on an affected host, so pushes require--no-verify— which also skips the signing and sign-off checks that hook enforces.Suggested Fix
Assert through the same semantics the product uses: capture a
ProcessIdentityfor the descendant before the stop and checkis_exited(identity_state(&grandchild))afterwards. A regression test pinning the zombie semantics would stop the weaker check from creeping back in.