Skip to content

Fix timeout overflow and IOCP rounding; validate timer arithmetic and heap invariants - #110

Merged
egorsmkv merged 5 commits into
masterfrom
fix/math-invariants
Oct 10, 2026
Merged

egorsmkv merged 5 commits into
masterfrom
fix/math-invariants

Conversation

@egorsmkv

@egorsmkv egorsmkv commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Mathematical review of master 5f5027c after #109 found two reproducible numerical edge cases:

  • shutdown_default_executor(timeout=2**64) and sys.float_info.max panic in Duration::from_secs_f64 after the shutdown worker starts.
  • IOCP conversion truncates every positive timeout below 1 ms to zero, turning an intended wait into immediate polling.

Use fallible, saturating conversion for positive finite executor timeouts, preserving completion and cancellation. Round finite IOCP waits up to milliseconds and cap below INFINITE. Existing ordinary timeout behavior, public signatures and dependencies remain unchanged.

The integer IOCP rule is m = min(ceil(n / 1,000,000), 2**32 - 2). Before saturation its quantization error is nonnegative and strictly below 1 ms; this is not a bound on OS wake latency. Microsoft documents zero as an immediate timeout. The conversion remains allocation-free and constant-time; Windows CPU/latency performance was not measured locally.

Validation additions:

  • Public API tests around the binary64/Duration boundary plus cancellation while the shutdown worker is blocked. Baseline: two RustPanic failures; fixed: all four tests pass.
  • Exact integer inequalities over all 2,000,001 nanosecond values from 0 through 2 ms and cap/extreme boundaries. Baseline fails at 1 ns; fixed passes.
  • Euclidean remainder invariants on 56 Duration boundary pairs and 8,256 whole-period translations.
  • 32,768 deterministic timer operations compared with an independent BTreeMap oracle, checking minimum/tie order, stale cancellation, wake order and heap/slab consistency after each operation.

Executed on Linux x86_64 / CPython 3.14.7 / Rust nightly-2026-09-25:

  • Release build, root/runtime-harness Clippy all targets/all features with warnings denied, formatting, changed Python Ruff and focused Pyright: passed.
  • Rust: 331 passed / 15 failed (default); 427 passed / 19 failed (all features). All failures report EPERM from unavailable io_uring or Unix-socket operations.
  • Python with local Redis: 477 passed / 2 Unix-socket EPERM failures / 3 skips; tooling separately 98 passed. Redis/hiredis ran against asyncio, uvloop and rsloop.
  • Hotpath audit: 2079 definitions, zero missing hooks; its 3 tests pass.

Full local suites are not green because of those restrictions. Windows/macOS, free-threaded Python and working io_uring were not executed locally. IOCP scalar arithmetic is tested on Linux under the existing test configuration. These bounded model tests are not a formal proof; generation wraparound is outside their scope.

See docs/math-validation.md for the requirement-to-test matrix, numerical risk ledger, derivation, reproducible seeds and verification limits.

CI follow-up (1bd0132): the initial Linux / Python 3.15t job exposed a stream-connection race: fast_open_connection_result borrowed the protocol on a smol worker while loop callbacks held a mutable borrow. Reproduced locally with Python 3.15.0rc3 free-threaded and the GIL disabled. Result assembly now follows a direct Python await on the loop thread, which also propagates cancellation to create_connection instead of abandoning its inner task. Added immediate-peer-close stress, thread/loop/context affinity, connection error and cancellation tests. Fixed free-threaded build: 12,800 stress connections passed; full suite 416 passed, 2 Unix-socket EPERM failures, 68 skips. CPython 3.14 release suite: 481 passed, 2 Unix-socket EPERM failures, 3 skips. Clippy all targets/all features, focused Pyright, Ruff, formatting, MkDocs and hotpath audit pass. On that commit, Linux / Python 3.15t passed in GitHub CI (418 tests, 68 skips); earlier local limitations above describe the initial mathematical review, before this free-threaded follow-up.

STARTTLS fixture follow-up (ba346a8): Windows CPython 3.11.9 intermittently failed in the stdlib ProactorEventLoop comparison after the client handshake completed and the server stayed pending. Explicit start events and pausing baseline plaintext reads prevent the separate early-ClientHello buffering race (cf. python/cpython#142352), but did not eliminate the Proactor failure. A diagnostic run with a longer deadline passed in under 0.19 s; that is not evidence that the original 3-second deadline was too short. The final comparison explicitly uses asyncio.SelectorEventLoop consistently across platforms, alongside uvloop where available and native rsloop. Original deadlines are restored and temporary tracing is removed. This does not fix or verify stdlib Proactor STARTTLS; Windows rsloop/IOCP STARTTLS remains covered in both upgrade orders. The runner now reports the ten slowest tests. Local final TLS/tooling validation: 128 passed, one existing Unix-socket EPERM failure; Ruff and focused Pyright pass. Tooling alone: 98 passed. Final-head CI (ba346a8): Tests run 38042522678 passed all 38 jobs, including Rust default/all-features, Clippy, Miri, hotpath/tooling and Linux/macOS/Windows Python matrices. Windows/Python 3.11: 395 passed, 91 skipped, 98 deselected. Linux/Python 3.15t passed. MkDocs also passed. Windows/macOS results are from GitHub Actions, not local execution.

@egorsmkv
egorsmkv merged commit 3ff820a into master Oct 10, 2026
40 checks passed
@egorsmkv
egorsmkv deleted the fix/math-invariants branch October 10, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant