Don't share or reuse timeout_completion

Results in undefined behavior when a client disconnects and another reconnects
while the timeout is being monitored:

https://github.com/lightpanda-io/browser/pull/436#issuecomment-2670455216
This commit is contained in:
Karl Seguin
2025-02-20 23:56:55 +08:00
parent b12eef218a
commit e301ba0cdb

View File

@@ -64,11 +64,12 @@ const Server = struct {
// a memory poor for our Clietns // a memory poor for our Clietns
client_pool: std.heap.MemoryPool(Client), client_pool: std.heap.MemoryPool(Client),
timeout_completion_pool: std.heap.MemoryPool(Completion),
// I/O fields // I/O fields
conn_completion: Completion, conn_completion: Completion,
close_completion: Completion, close_completion: Completion,
accept_completion: Completion, accept_completion: Completion,
timeout_completion: Completion,
// The response to send on a GET /json/version request // The response to send on a GET /json/version request
json_version_response: []const u8, json_version_response: []const u8,
@@ -76,6 +77,7 @@ const Server = struct {
fn deinit(self: *Server) void { fn deinit(self: *Server) void {
self.send_pool.deinit(); self.send_pool.deinit();
self.client_pool.deinit(); self.client_pool.deinit();
self.timeout_completion_pool.deinit();
self.allocator.free(self.json_version_response); self.allocator.free(self.json_version_response);
} }
@@ -121,11 +123,16 @@ const Server = struct {
} }
fn queueTimeout(self: *Server) void { fn queueTimeout(self: *Server) void {
const completion = self.timeout_completion_pool.create() catch |err| {
log.err("failed to create timeout completion: {any}", .{err});
return;
};
self.loop.io.timeout( self.loop.io.timeout(
*Server, *Server,
self, self,
callbackTimeout, callbackTimeout,
&self.timeout_completion, completion,
TimeoutCheck, TimeoutCheck,
); );
} }
@@ -135,8 +142,7 @@ const Server = struct {
completion: *Completion, completion: *Completion,
result: TimeoutError!void, result: TimeoutError!void,
) void { ) void {
std.debug.assert(completion == &self.timeout_completion); self.timeout_completion_pool.destroy(completion);
const client = self.client orelse return; const client = self.client orelse return;
if (result) |_| { if (result) |_| {
@@ -1008,10 +1014,10 @@ pub fn run(
.conn_completion = undefined, .conn_completion = undefined,
.close_completion = undefined, .close_completion = undefined,
.accept_completion = undefined, .accept_completion = undefined,
.timeout_completion = undefined,
.json_version_response = json_version_response, .json_version_response = json_version_response,
.send_pool = std.heap.MemoryPool(Send).init(allocator), .send_pool = std.heap.MemoryPool(Send).init(allocator),
.client_pool = std.heap.MemoryPool(Client).init(allocator), .client_pool = std.heap.MemoryPool(Client).init(allocator),
.timeout_completion_pool = std.heap.MemoryPool(Completion).init(allocator),
}; };
defer server.deinit(); defer server.deinit();