Repository navigation
Conversation
machine-moon
reviewed
Nov 4, 2026
machine-moon
reviewed
Nov 4, 2026
machine-moon
reviewed
Nov 4, 2026
The threads of mod_http3 allocated from the child pool, which is not thread-safe, and kept running while it was destroyed: - The port acquirer thread, in every child that does not own the UDP port, created a socket in the child pool every 200 ms, racing with the main thread and never freeing it. - Under prefork the child pool's allocator has no mutex and is shared with the request pools, which the event thread raced with when it created connection pools. - prefork does not run the child_stopping hook when a child exits from a signal handler, so neither thread was stopped before the child pool was destroyed and exit() ran OpenSSL's cleanup under them. These crashed children with SIGSEGV on stop, mostly under prefork. Give mod_http3 a pool of its own with a locked allocator, give each port acquisition attempt a scratch pool that is cleared on retry, and stop the threads from a pre-cleanup of the child pool as well. Generated-by: Claude Code (Claude Opus 5.5)
Review feedback: keep the body of stop_child_threads() in h3_c1_child_stopping(), which the child pool cleanup now calls, so no forward declaration is needed. Move the pool creation to h3_threads.c so other code can reuse it. * modules/http3/h3_server.c (h3_c1_child_stopping): Fold in stop_child_threads(). * modules/http3/h3_threads.c, modules/http3/include/h3_threads.h (h3_thread_safe_pool_create): New, from create_h3_pool() in h3_server.c. Generated-by: Claude Code (Claude Opus 5.5)
Review feedback: the mutex on the allocator of the HTTP/3 pool covers subpools, not allocations from the pool itself. h3_io_listen_start() registered its pool cleanup after starting the event thread, which allocates from the same pool, so the two could allocate at once when the port acquirer thread started listening. Register it first. Also destroy the pool when its mutex cannot be created, log when the port acquirer cannot create its pool, drop an empty APLOGNO() that no other message in the file has, and keep the declarations in h3_child_init() at the top of their blocks, as C89 requires. * modules/http3/h3_io.c (h3_io_listen_start): Register the cleanup before starting the event thread. * modules/http3/h3_server.c (port_acquire_thread_fn): Log the pool creation failure. (h3_child_init): Declare variables first; drop the APLOGNO(). * modules/http3/h3_threads.c (h3_thread_safe_pool_create): Destroy the pool if its mutex cannot be created. * modules/http3/include/h3_threads.h: Say what the mutex does not cover. Generated-by: Claude Code (Claude Opus 5.5)
mbeijen
force-pushed
the
h3-child-pool
branch
from
November 4, 2026 19:05
71de859 to
4325ba9
Compare
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.
The threads of mod_http3 allocated from the child pool, which is not thread-safe. Under prefork, its allocator has no mutex and is shared with every request pool. prefork also skips the
child_stoppinghook when a child exits from a signal handler, so the threads could still be running while the child pool was destroyed. Children crashed with SIGSEGV on stop, mostly under prefork.This gives mod_http3 a pool of its own with a locked allocator, and gives each port acquisition attempt a scratch pool that is cleared on retry (each retry used to leak a socket into the child pool). It also stops the threads from a pre-cleanup of the child pool.
SECURITY.mdand https://www.apache.org/security/#reporting-a-vulnerability).APLOGNO()tag; numbers are assigned by a committer at merge time (seedocs/log-message-tags/README).changes-entries/*.txtfile is included, following the template inREADME.CHANGES(not needed otherwise).test/modules/xxxdirectory matching themodules/xxxmodule source, ortest/modules/corefor core server changes. On Unix, verify these pass locally with e.g.make check-pytest PYTEST_DIRS=test/modules/xxx.