Skip to content

Commit cc5e9cc

Browse files
committed
fix(qwp): Error inside upgrade-failure catch arm leaks the connected client
The catch (HttpClientException) arm ran QwpUpgradeFailures.classify() before newClient.close(). The sibling catch (Error) added in 1582e3a does not guard catch-arm bodies, so an Error thrown inside classify (it allocates on the role-reject/auth paths) escaped with the client's fd and native buffers open -- the exact leak 1582e3a set out to close. Reorder: close before classify. Safe -- classify reads only heap fields (upgradeRejectRole/Zone, upgradeStatusCode) that are set during upgrade() and are not cleared by close(). The arm now has a zero-allocation window ahead of close().
1 parent 0f3d3d3 commit cc5e9cc

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpWebSocketSender.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2768,8 +2768,15 @@ private WebSocketClient connectWalk(ReconnectSupplier ctx) {
27682768
int upgradeTimeoutMs = (int) Math.min(authTimeoutMs, Integer.MAX_VALUE);
27692769
newClient.upgrade(WRITE_PATH, upgradeTimeoutMs, authorizationHeader);
27702770
} catch (HttpClientException e) {
2771-
HttpClientException classified = QwpUpgradeFailures.classify(newClient, ep.host, ep.port, e);
2771+
// Close BEFORE classify: the sibling catch (Error) below does not
2772+
// guard catch-arm bodies, so an Error thrown inside classify()
2773+
// (it allocates on the role-reject/auth paths) would escape with
2774+
// the client's fd and native buffers open. Safe to reorder --
2775+
// classify reads only heap fields (upgradeRejectRole/Zone,
2776+
// upgradeStatusCode) that are set during upgrade() and survive
2777+
// close().
27722778
newClient.close();
2779+
HttpClientException classified = QwpUpgradeFailures.classify(newClient, ep.host, ep.port, e);
27732780
if (classified instanceof QwpIngressRoleRejectedException) {
27742781
QwpIngressRoleRejectedException re = (QwpIngressRoleRejectedException) classified;
27752782
hostTracker.recordRoleReject(idx, re.isTransient(), !background);

0 commit comments

Comments
 (0)