fix(kqueue): fix a possible fd leak on add_watch races

This commit is contained in:
CJ van den Berg 2026-03-14 18:47:57 +01:00
parent 8e307e5863
commit 338c8460ff
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
2 changed files with 18 additions and 0 deletions

View file

@ -274,6 +274,12 @@ fn register_file_watch(self: *@This(), allocator: std.mem.Allocator, path: []con
return; return;
}; };
self.file_watches_mutex.lock(); self.file_watches_mutex.lock();
if (self.file_watches.contains(path)) {
self.file_watches_mutex.unlock();
std.posix.close(fd);
allocator.free(owned);
return;
}
self.file_watches.put(allocator, owned, fd) catch { self.file_watches.put(allocator, owned, fd) catch {
self.file_watches_mutex.unlock(); self.file_watches_mutex.unlock();
std.posix.close(fd); std.posix.close(fd);
@ -350,6 +356,12 @@ pub fn add_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8)
}; };
const owned_path = try allocator.dupe(u8, path); const owned_path = try allocator.dupe(u8, path);
self.watches_mutex.lock(); self.watches_mutex.lock();
if (self.watches.contains(path)) {
self.watches_mutex.unlock();
std.posix.close(path_fd);
allocator.free(owned_path);
return;
}
self.watches.put(allocator, owned_path, path_fd) catch |e| { self.watches.put(allocator, owned_path, path_fd) catch |e| {
self.watches_mutex.unlock(); self.watches_mutex.unlock();
allocator.free(owned_path); allocator.free(owned_path);

View file

@ -315,6 +315,12 @@ pub fn add_watch(self: *@This(), allocator: std.mem.Allocator, path: []const u8)
const is_file = if (stat) |s| std.posix.S.ISREG(s.mode) else false; const is_file = if (stat) |s| std.posix.S.ISREG(s.mode) else false;
const owned_path = try allocator.dupe(u8, path); const owned_path = try allocator.dupe(u8, path);
self.watches_mutex.lock(); self.watches_mutex.lock();
if (self.watches.contains(path)) {
self.watches_mutex.unlock();
std.posix.close(path_fd);
allocator.free(owned_path);
return;
}
self.watches.put(allocator, owned_path, .{ .fd = path_fd, .is_file = is_file }) catch |e| { self.watches.put(allocator, owned_path, .{ .fd = path_fd, .is_file = is_file }) catch |e| {
self.watches_mutex.unlock(); self.watches_mutex.unlock();
allocator.free(owned_path); allocator.free(owned_path);