Compare only settable descriptor status flags in the PTY session test

Merged
VA
2d ago
+43-8

Class

Two PTY restoration tests compared raw F_GETFL flags: term::session::tests::delayed_old_state_drop_preserves_reopened_pty and the integration test controlling_tty_probe_and_os_state_restore (tests/terminal.rs). Both fail on macOS (ivar) on clean main and pass on Linux (bb1):

left: OFlags(NONBLOCK | RDWR | 0x10000)
right: OFlags(NONBLOCK | RDWR)

Root cause

The comparison was too strict. The reopened PTY does not differ.

0x10000 is XNU's kernel-private FWASWRITTEN ("descriptor was written"). F_GETFL reports it once anything has been written through the open file description, and F_SETFL can neither set nor clear it. The test captured flags before the session wrote its terminal probe, so every later read on macOS had the extra bit.

A direct check on ivar (Python fcntl, on a fresh pty):

stepF_GETFL
open0x2
F_SETFL with NONBLOCK0x6
after one write0x10006
F_SETFL with the saved flags0x10002
dup of it0x10002

Production (tty.rs) restores with F_SETFL from the saved flags, which is correct. The bit is not state a session can save or restore.

Change

  • One helper, settable_status_flags in tests/support/status_flags.rs, is the only way either restoration test reads descriptor flags. The unit test includes it with #[path], the integration test as a module, and neither test calls fcntl_getfl any more.

  • The helper selects exactly the flags F_SETFL can change, rather than excluding known extras:

    • Darwin: xnu FCNTLFLAGS (bsd/sys/fcntl.h), which is FAPPEND | FASYNC | FFSYNC | FFDSYNC | FNONBLOCK.
    • Linux: the fcntl(2) settable set, which is O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK.
    • Other unix: O_APPEND | O_NONBLOCK.

    The access mode (O_RDWR) and FWASWRITTEN are fixed for the open file, so they are no longer compared.

Validation

wherecommandresult
ivar (macOS 15.6), at 1f11a1f9d--lib term::session; --test terminal controlling_tty1 passed each, 0.00 s / 0.60 s (both failed before)
ivarnegative control: restore leaves NONBLOCK set (tty.rs:55)both tests fail, NONBLOCK vs 0x0
bb1 (Linux), at 1f11a1f9dthe same two tests1 passed each, 0.00 s
bb1Windows GNU cargo check -p acyclic-harness-tui --features tui --lib --testsok
ivar (macOS 15.6), first revisioncargo test --locked -p acyclic-harness-tui --features tui --lib term::2 passed, 3 reruns (failed before the change)
ivarthe full acyclic-harness-tui --features tui lib suite14 passed
ivarnegative control: restore leaves NONBLOCK set (tty.rs)the test fails, NONBLOCK | RDWR vs RDWR
ivarrustfmt --check, clippyclean for session.rs
bb1 (Linux)cargo test --locked -p acyclic-harness-tui --features tui --lib term::2 passed

Decisions

  • Select the settable set, rather than mask known extras or capture the baseline after a write. Selecting what F_SETFL can change is exactly the state a session saves and restores, so a new kernel bookkeeping bit cannot break the tests and a leaked settable flag (such as NONBLOCK) still fails them. A baseline taken after a write would hide the reason and depend on test ordering.
  • Keep the helper in tests/support, shared by #[path]. That keeps it out of the library's public surface, and there is one definition for both tests.
  • No production change. Restoring through F_SETFL already ignores bits that cannot be set.

šŸ¤– Generated with Claude Code