Skip to content

[Issue]: Process-tree tests count a zombie as running, failing on hosts that reap slowly #168

Description

@rominf

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions