Skip to content

Use identity creation times for parent/child PID-reuse checks - #2912

Open
snowyukitty wants to merge 1 commit into
giampaolo:masterfrom
snowyukitty:fix/parent-children-ordering-ctime
Open

snowyukitty wants to merge 1 commit into
giampaolo:masterfrom
snowyukitty:fix/parent-children-ordering-ctime

Conversation

@snowyukitty

Copy link
Copy Markdown

Summary

Description

Process.parent() and Process.children() currently compare raw
create_time() values to reject parent-child relationships that look
chronologically impossible. Those calls bypass the platform-specific creation
time selected by Process._get_ident().

This change uses identity creation times for the ordering check, while retaining
the existing fresh Process(self.pid) lookup so an intervening process exit can
still raise NoSuchProcess. If an ordering time is unavailable, the check is
inconclusive and the observed relationship is preserved.

The platform behavior is:

  • Linux, NetBSD, and macOS use the monotonic process start time already used by
    psutil's PID-reuse detection.
  • FreeBSD, OpenBSD, SunOS, and AIX leave the ordering time unknown, so the
    chronological filter is disabled. This matches the existing PID-reuse FAQ,
    which documents that identity on those platforms is based on PID alone.
  • Windows normally uses its fast identity creation time. If that lookup was
    denied, the code retries through create_time(), whose slower fallback can
    still retrieve the timestamp for privileged processes. This preserves the
    stale-PPID/PID-reuse filtering restored by
    697513a.
    A valid 0.0 returned by the Windows fallback remains an ordering value. Only
    if the fallback also raises AccessDenied or ZombieProcess is the check
    treated as inconclusive; in that case the relationship is preserved instead
    of propagating the exception.

The tests cover known inverted times, null identity times on either side,
Windows fast-to-slow fallback (including a 0.0 result), denied fallback,
direct and recursive children(), and the fresh-self lookup retained from
#2542.

Validation

  • python setup.py build_ext -i --parallel 4: pass
  • pytest -q tests/test_process.py -k "null_ctime or refreshes_self or reused_pid":
    6 passed, 96 deselected
  • The same tests applied to the exact upstream base:
    12 failed, 6 passed, 96 deselected (expected red)
  • An intentional mutation removing the Windows fallback:
    5 failed, 6 passed, 96 deselected (all five fallback-success cells)
  • pytest -q tests/test_process.py -k "not test_open_files":
    75 passed, 25 skipped, 2 deselected
  • pytest -q tests/test_testutils.py tests/test_misc.py tests/test_contracts.py tests/test_system.py:
    169 passed, 13 skipped
  • A frozen-map Windows differential compared parent(), children(), and
    recursive children() for 566 live processes: zero decisions differed from
    the exact base, while a base-vs-base churn control differed in 13.
  • A 571-process Windows probe found 385 known fast identity times and 186 slow
    fallbacks, all successful; no process had both paths denied on this host.
    Hardened or low-integrity environments may exercise that defensive branch.
  • services.exe.children() measured about 1.46 seconds on the exact base and
    1.41-1.46 seconds with this patch, with 147-148 of about 160 children taking
    the slow path in both. An experimental no-fallback version took 14-17 ms, but
    reproduced the bogus-child regression reverted by 697513a; the speedup came
    from skipping a necessary check.
  • ruff check, black --check, and git diff --check: pass

The full tests/test_process.py run has one test_open_files Windows
subprocess race (1 failed, 76 passed, 25 skipped). The same failure reproduces
on the unmodified upstream base. Non-Windows platforms and
tests/test_memleaks.py were not run locally.

Use platform identity creation times for chronological relationship checks while retaining the Windows slow fallback for privileged processes. Preserve observed relationships only when ordering remains inconclusive, and cover null times, fallback behavior, recursion, and intervening process exits.
@github-actions github-actions Bot added the tests component : tests/ - the suite itself, not a bug it happens to catch label Jul 27, 2026
@giampaolo giampaolo added bug type and removed tests component : tests/ - the suite itself, not a bug it happens to catch labels Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug type

Projects

None yet

Development

Successfully merging this pull request may close these issues.

children() / parent() PID-reuse check may be incorrect

2 participants