From 870a682cd84e49b2213dffd59c9848d7fd12b7a1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 15 Oct 2025 11:01:03 -0700 Subject: [PATCH] std.Io.net.HostName.connect: fix resource leaks Must free other succeeded connections that lost the race. --- BRANCH_TODO | 1 + lib/std/Io/net/HostName.zig | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index 53b157f41efe90750c17a6e2d8bf0887a62cdbff..37739e7d824bd2e9a8672c7dde058879285f606b 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -18,3 +18,4 @@ * migrate child process into std.Io * eliminate std.Io.poll (it should be replaced by "select" functionality) * finish moving all of std.posix into Threaded +* TCP fastopen - sends initial payload along with connection. can be done for idempotent http requests diff --git a/lib/std/Io/net/HostName.zig b/lib/std/Io/net/HostName.zig index 75e69a6a7685132afa3d5a1de04c9b80b55f1ec4..6352d82dd03d4be8f51f42cd8a1090e9dadf649c 100644 --- a/lib/std/Io/net/HostName.zig +++ b/lib/std/Io/net/HostName.zig @@ -210,25 +210,38 @@ pub fn connect( var connect_many_queue: Io.Queue(ConnectManyResult) = .init(&connect_many_buffer); var connect_many = io.async(connectMany, .{ host_name, io, port, &connect_many_queue, options }); - defer connect_many.cancel(io); + var saw_end = false; + defer { + connect_many.cancel(io); + if (!saw_end) while (true) switch (connect_many_queue.getOneUncancelable(io)) { + .connection => |loser| if (loser) |s| s.closeConst(io) else |_| continue, + .end => break, + }; + } var aggregate_error: ConnectError = error.UnknownHostName; while (connect_many_queue.getOne(io)) |result| switch (result) { .connection => |connection| if (connection) |stream| return stream else |err| switch (err) { - error.SystemResources => |e| return e, - error.OptionUnsupported => |e| return e, - error.ProcessFdQuotaExceeded => |e| return e, - error.SystemFdQuotaExceeded => |e| return e, - error.Canceled => |e| return e, + error.SystemResources, + error.OptionUnsupported, + error.ProcessFdQuotaExceeded, + error.SystemFdQuotaExceeded, + error.Canceled, + => |e| return e, + error.WouldBlock => return error.Unexpected, + else => |e| aggregate_error = e, }, .end => |end| { + saw_end = true; try end; return aggregate_error; }, - } else |err| return err; + } else |err| switch (err) { + error.Canceled => |e| return e, + } } pub const ConnectManyResult = union(enum) { @@ -255,7 +268,6 @@ pub fn connectMany( }); var group: Io.Group = .init; - defer group.cancel(io); while (lookup_queue.getOne(io)) |dns_result| switch (dns_result) { .address => |address| group.async(io, enqueueConnection, .{ address, io, results, options }), @@ -266,7 +278,10 @@ pub fn connectMany( return; }, } else |err| switch (err) { - error.Canceled => |e| results.putOneUncancelable(io, .{ .end = e }), + error.Canceled => |e| { + group.cancel(io); + results.putOneUncancelable(io, .{ .end = e }); + }, } } -- 2.54.0