#143 fuzzy-tests: chaos coverage gaps — proc_open, curl_multi, feof, flock, SSL accept, socket ext#147
Merged
EdmondDantes merged 6 commits intoMay 25, 2026
Conversation
First Layer-3 (process) chaos: four coroutines cycling proc_open + proc_close hammer the reactor's process_events hashtable under random scheduling. Backstops tests/exec/011-proc_open_handle_reuse_uaf with concurrent open/close instead of sequential. The parked-fread-vs-close scenarios surfaced a real reactor bug while being drafted: proc_terminate + proc_close does not wake a parked fread() on the child's stdout pipe; the deadlock detector eventually aborts the request. Reproduced outside the harness in ~25 lines, filed as #144. Those scenarios are kept commented in the feature so they can be reinstated by uncomment once the fix lands. Context: new $processes registry + teardown. Steps: long-lived child, reads stdout, closes (terminate+reap), SIGTERM, storm (proc_open+proc_close N times). generate.php: new SKIPIF tag `proc-open` (POSIX-only, requires TEST_PHP_EXECUTABLE). Storm scenario green under fifo + 4 random seeds, plus ASAN-ZTS. Full fuzzy-tests suite (735 phpt) stays 100% pass. Umbrella: #143
… cancel) First chaos coverage of ext/curl/curl_async.c's curl_multi_select() reactor integration (single-handle curl_exec already covered by #136). One coroutine attaches N easy handles to one curl_multi_init() and drives the standard exec/select loop; per-handle CURLMSG_DONE drains into outcome buckets. Three scenarios shipped: - three peers, all return intact; - one peer aborts mid-body, others still complete; - two coroutines each owning their own multi handle. The three planned cancel-mid-multi-select scenarios surfaced a real heap-corruption bug: AsyncCancellation interrupting curl_multi_select() corrupts the zend allocator free-list and the next coroutine SEGVs in zend_mm_alloc_small. Reproduced in ~50 lines outside the harness on ASAN-ZTS. Filed as #145; the scenarios stay commented in the feature under `# Blocked: #145` for one-line reinstatement after the fix. 3 .phpt × 4 random seeds green, plus ASAN-ZTS. Full fuzzy suite stays at 100% pass. Umbrella: #143
ext/async/tests/stream/038–044 pin the deterministic feof() return value at specific points; this feature crosses them into chaos. A writer pushes N bytes then closes the write end, a reader drains via canonical `while (!feof) fread` loop, an optional third coroutine spams feof() from a sibling context. Invariants: drain loop receives every byte BEFORE feof becomes true (no premature-EOF data loss), drain/cancel/fail outcomes sum to attempts. Steps: `drains shared pipe ... with feof loop` (counter family feof_drain_* incl. feof_drain_bytes) and `polls feof of shared pipe ... N times` (feof_poll_*). 6 .phpt × 5 seeds green, plus ASAN-ZTS. Umbrella: #143
…on cancel) ext/async/tests/io/081-flock_non_blocking_event_loop.phpt pins one deterministic shape; this feature fuzzes the contention surface — four coroutines contend for one LOCK_EX, plus holder + two waiters all eventually acquire. Two cancel-mid-flock scenarios surfaced a real stack-use-after-return in main/streams/plain_wrapper.c:1192: the flock task struct lives on the caller's stack but the libuv worker keeps writing to it after the coroutine unwinds on cancel. Confirmed by ASAN-ZTS trace pointing at plain_wrapper.c:1097. Filed as #146; cancel scenarios stay commented under `# Blocked: #146` for one-line reinstatement after fix. Context: $lockFiles registry, unlink in __destruct. Steps: shared lock file, acquire LOCK_EX + release after N ms. 2 .phpt × 3 random seeds green, plus ASAN-ZTS. Umbrella: #143
tests/stream/027-ssl_concurrent_accept.phpt pins the deterministic "three SSL servers each accept one client" shape; the existing tls_connect.feature (#138) covers client-side cancellation. This feature is the accept-side mirror: - three independent ssl:// servers each accept one client (027 under random scheduling); - one server fans in four concurrent TLS clients; - acceptor cancelled while parked in stream_socket_accept() (timing sweep 0 / 5 / 50 / 200 ms). Reuses existing TLS server + TLS client steps. 7 .phpt × 5 random seeds green, plus ASAN-ZTS. No findings — the SSL accept path is solid. Umbrella: #143
First chaos coverage of the ext/sockets API path (xp_socket.c / network_async.c), distinct from the streams layer covered by cancel_during_connect / udp_chaos / cancel_during_io. Three verbs on the cancel surface: - socket_connect to TCP blackhole (cancel-timing sweep 0/5/50 ms); - socket_recvfrom on fresh bound UDP socket; - socket_accept on fresh TCP listener. Confirmed ext/sockets is reactor-integrated via separate probe (recvfrom parks ~50 ms before cancellation lands). 6 .phpt × 4 random seeds green, plus ASAN-ZTS. No findings. Umbrella: #143
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Umbrella #143: closes the chaos-coverage white zones identified after #138 (Layer 1+2 IO) merged. Six new features under
fuzzy-tests/, 21 .phpt total, green on fifo + 3–5 random seeds and ASAN-ZTS.Coverage added
exec/proc_open_chaoscurl/curl_multi_chaosio/feof_chaosio/flock_chaosio/ssl_accept_chaosio/socket_ext_chaosFindings filed while drafting
Three real bugs surfaced — all confirmed by minimal repros (≤50 lines) outside the harness; ASAN traces or deadlock-detector reports attached on each issue. The blocked scenarios are kept commented in the feature files under
# Blocked: #Nfor one-line reinstatement after each fix.fread()on aproc_openchild's pipe when the child is externallyproc_terminate'd +proc_close'd. Deadlock detector eventually aborts. Mirror dance withstream_socket_pairworks fine, so the gap is on thepipe(2)reactor path.curl_multiheap corruption:AsyncCancellationinterruptingcurl_multi_select()corrupts the zend allocator free-list; next coroutine SEGVs inzend_mm_alloc_small. Reproducible on ASAN-ZTS.flock()stack-use-after-return:main/streams/plain_wrapper.c:1192puts the task struct on the caller's stack, libuv worker keeps writing to it after the coroutine unwinds on cancel. ASAN points toplain_wrapper.c:1097directly.Harness additions
Context::$processes,Context::$lockFilesregistries + teardownproc-open,socketsSKIPIF tagsStandardSteps::curlMulti()helper mirroringcurlGet()Test plan