termio: release initial input resources (#13931)

Initial input files remained open and their fully read buffers remained
allocated after queueWrite copied their contents. Close these files on
both startup success and failure, free their contents after queueing,
and borrow raw values already owned by the arena.

**AI Usage:** This was spotted by GPT 5.6 Sol. I reworked the code a bit
and understand it all.
This commit is contained in:
Mitchell Hashimoto
2026-08-20 06:56:43 -07:00
committed by GitHub

View File

@@ -119,13 +119,15 @@ const ThreadEnterState = struct {
) (Allocator.Error || error{InputNotFound})![]const Input {
const alloc = self.arena.allocator();
var input = try alloc.alloc(
Input,
var inputs: std.ArrayList(Input) = try .initCapacity(
alloc,
self.input.list.items.len,
);
for (self.input.list.items, 0..) |item, i| {
input[i] = switch (item) {
.raw => |v| .{ .string = try alloc.dupe(u8, v) },
errdefer for (inputs.items) |item| item.deinit();
for (self.input.list.items) |item| {
inputs.appendAssumeCapacity(switch (item) {
.raw => |v| .{ .string = v },
.path => |path| file: {
const f = std.Io.Dir.cwd().openFile(
global.io(),
@@ -141,15 +143,22 @@ const ThreadEnterState = struct {
break :file .{ .file = f };
},
};
});
}
return input;
return inputs.items;
}
const Input = union(enum) {
string: []const u8,
file: std.Io.File,
fn deinit(self: Input) void {
switch (self) {
.string => {},
.file => |f| f.close(global.io()),
}
}
};
};
@@ -346,6 +355,9 @@ pub fn threadEnter(
try v.prepareInput()
else
null;
defer if (inputs) |items| {
for (items) |input| input.deinit();
};
data.* = .{
.alloc = self.alloc,
@@ -366,20 +378,21 @@ pub fn threadEnter(
log.warn("failed to queue input string err={}", .{err});
return error.InputFailed;
},
.file => |f| self.queueWrite(
data,
compat_file.readToEndAlloc(
.file => |f| {
const contents = compat_file.readToEndAlloc(
f,
self.alloc,
10 * 1024 * 1024, // 10 MiB max
) catch |err| {
log.warn("failed to read input file err={}", .{err});
return error.InputFailed;
},
false,
) catch |err| {
log.warn("failed to queue input file err={}", .{err});
return error.InputFailed;
};
defer self.alloc.free(contents);
self.queueWrite(data, contents, false) catch |err| {
log.warn("failed to queue input file err={}", .{err});
return error.InputFailed;
};
},
};
}