Background
#471 / #472 fixed the primary port-reservation race in libtest::Server::start(): get_free_port() now keeps its reservation socket bound until the caller explicitly calls release_port(), and Server::start() releases its own _port once the server is confirmed up (or definitively failed) via an RAII guard.
That fix only releases the Server object's own _port. Several call sites use get_free_port() to reserve a port for something other than the Server's primary port — e.g.:
tests/httpd_test.cc:149 — http_port is reserved and passed as --http-port= to a gearmand instance whose Server::_port is actually default_port(). The Server never knows about http_port, so its reservation is never released.
tests/gearmand.cc:190,549 (long_keepalive_start_TEST, config_file_SIMPLE_TEST) — ports reserved via get_free_port() for --check-args runs that don't go through a Server object at all.
In all of these, the reservation socket now stays open (bound, unreleased) for the remaining lifetime of the test process instead of being freed once it's no longer needed.
Impact
Low severity — this does not reintroduce the original race (holding a reservation longer than necessary is safe, just wasteful). The practical effect is a growing number of open file descriptors / permanently-occupied ephemeral ports for the rest of a given test binary's run. Unlikely to cause failures on its own, but wastes resources and could compound in long-running or -j-parallel test invocations.
Suggested fix
Give these call sites an explicit release_port(port) once the port is no longer needed (e.g. after the associated server/process is confirmed started, or via a scoped RAII guard similar to the one added in Server::start()). Would need to audit all get_free_port() call sites under tests/ to find which ones aren't already covered by a Server::start()/release_port() pair.
References
🤖 Generated with Claude Code
Background
#471 / #472 fixed the primary port-reservation race in
libtest::Server::start():get_free_port()now keeps its reservation socket bound until the caller explicitly callsrelease_port(), andServer::start()releases its own_portonce the server is confirmed up (or definitively failed) via an RAII guard.That fix only releases the
Serverobject's own_port. Several call sites useget_free_port()to reserve a port for something other than theServer's primary port — e.g.:tests/httpd_test.cc:149—http_portis reserved and passed as--http-port=to a gearmand instance whoseServer::_portis actuallydefault_port(). TheServernever knows abouthttp_port, so its reservation is never released.tests/gearmand.cc:190,549(long_keepalive_start_TEST,config_file_SIMPLE_TEST) — ports reserved viaget_free_port()for--check-argsruns that don't go through aServerobject at all.In all of these, the reservation socket now stays open (bound, unreleased) for the remaining lifetime of the test process instead of being freed once it's no longer needed.
Impact
Low severity — this does not reintroduce the original race (holding a reservation longer than necessary is safe, just wasteful). The practical effect is a growing number of open file descriptors / permanently-occupied ephemeral ports for the rest of a given test binary's run. Unlikely to cause failures on its own, but wastes resources and could compound in long-running or
-j-parallel test invocations.Suggested fix
Give these call sites an explicit
release_port(port)once the port is no longer needed (e.g. after the associated server/process is confirmed started, or via a scoped RAII guard similar to the one added inServer::start()). Would need to audit allget_free_port()call sites undertests/to find which ones aren't already covered by aServer::start()/release_port()pair.References
🤖 Generated with Claude Code