Skip to content

Bug Fixes - #40

Open
vijayee wants to merge 4 commits into
Prometheus-SCN:masterfrom
vijayee:master
Open

Bug Fixes#40
vijayee wants to merge 4 commits into
Prometheus-SCN:masterfrom
vijayee:master

Conversation

@vijayee

@vijayee vijayee commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Bug Fixes

Two races identified by TSAN (ASAN and valgrind miss them) caused heap
corruption that surfaced as NULL buffer->data in HTTP body handlers:

1. connection->sock use-after-free: _connection_close_fd (worker thread)
   freed the socket and set connection->sock = NULL while
   _connection_read_callback (I/O thread) read it. Fixed by making
   connection->sock an ATOMIC(platform_socket_t*) and deferring the
   socket's close+free to the I/O thread's destroy stack via
   http_server_defer_socket_destroy, mirroring the existing
   watcher/timer deferral.

2. pipe_notifiers use-after-free WRITE: readable_push_stream_pipe /
   writeable_pull_stream_pipe called on_pipe/on_piped synchronously
   on the caller's thread, writing pipe_notifiers while
   stream_unsubscribe_pipe_notifiers (worker thread) freed it. Fixed
   by routing pipe/piped through the stream actor via the
   already-declared STREAM_PIPE/STREAM_PIPED messages and
   stream_pipe_internal/stream_piped_internal.

server_destroy_node_t generalized from is_timer bool to a type enum
(0=watcher, 1=timer, 2=socket) to support deferred socket destruction.

Verified: TestPushFileStream.*, TestPullFileStream.*, TestStreamActor.*,
TestHttpServer.*, TestOffRoutes.*, TestHttpServerSsl.* pass under TSAN
with zero data-race reports; full 849-test suite passes.
The get_pipeline_t refcount never reached zero, leaking 48 bytes (the
struct) + 209 bytes indirect (the ori_t) per GET request.

Root cause: refcounter_init + 4x refcounter_reference created 5 refs,
but only 2-3 derefs happened. stream_deactivate emits both close_event
and error_event, so desc contributes 1 or 2 derefs depending on path
(normal close = 1, deactivate = 2), while rs contributes 1. The
asymmetric deref count meant no path reached zero.

Fix: add a desc_done flag so desc contributes exactly one deref
(whichever of close or error fires first sets the flag and derefs;
the other is a no-op). Reduce refs to init + 1x reference = 2 refs,
matching the 2 derefs (desc-done + rs-done) in all paths.

Verified: 7 TestOffRoutes tests pass under valgrind with 0 leaks
(was: 48 bytes direct + 209 bytes indirect in _setup_stream_pipeline).
…n-flaky

The test called srand(2) expecting rand() determinism, but
store_block_should_accept draws from platform_random_uniform_float
(CSPRNG via getentropy on Linux), which srand() cannot seed. Each run
had a 75% chance of passing — observed 2-of-3 pass rate.

Replaced the single-trial assertion with a 2000-trial statistical
check: at capacity=0.2, INHALE phase, accept_probability=0.75, so
expected accepts = 1500 ± 100 (≈5.2σ band, ~1-in-5M false-fail rate).

Verified: 5/5 consecutive runs pass; full 849-test suite passes.
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