Files
ghostty/src/os/file.zig
Jonathan Marler e1996ad1e5 os: remove UB, tmpDir is returning stack memory on Windows
On Windows, the tmpDir function is currently using a buffer on the stack
to convert the WTF16-encoded environment variable value "TMP" to utf8
and then returns it as a slice...but that stack buffer is no longer valid
when the function returns.  This was causing the "image load...temporary
file" test to fail on Windows.

I've updated the function to take an allocator but it only uses
the allocator on Windows.  No allocation is needed on other platforms
because they return environment variables that are already utf8 (ascii)
encoded, and the OS pre-allocates all environment variables in the process.
To keep the conditional that determines when allocation is required, I
added the `freeTmpDir` function.
2024-02-10 21:09:05 -07:00

70 lines
2.3 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const log = std.log.scoped(.os);
/// This maximizes the number of file descriptors we can have open. We
/// need to do this because each window consumes at least a handful of fds.
/// This is extracted from the Zig compiler source code.
pub fn fixMaxFiles() void {
if (!@hasDecl(std.os.system, "rlimit")) return;
const posix = std.os;
var lim = posix.getrlimit(.NOFILE) catch {
log.warn("failed to query file handle limit, may limit max windows", .{});
return; // Oh well; we tried.
};
// If we're already at the max, we're done.
if (lim.cur >= lim.max) {
log.debug("file handle limit already maximized value={}", .{lim.cur});
return;
}
// Do a binary search for the limit.
var min: posix.rlim_t = lim.cur;
var max: posix.rlim_t = 1 << 20;
// But if there's a defined upper bound, don't search, just set it.
if (lim.max != posix.RLIM.INFINITY) {
min = lim.max;
max = lim.max;
}
while (true) {
lim.cur = min + @divTrunc(max - min, 2); // on freebsd rlim_t is signed
if (posix.setrlimit(.NOFILE, lim)) |_| {
min = lim.cur;
} else |_| {
max = lim.cur;
}
if (min + 1 >= max) break;
}
log.debug("file handle limit raised value={}", .{lim.cur});
}
/// Return the recommended path for temporary files.
/// This may not actually allocate memory, use freeTmpDir to properly
/// free the memory when applicable.
pub fn allocTmpDir(allocator: std.mem.Allocator) ?[]const u8 {
if (builtin.os.tag == .windows) {
// TODO: what is a good fallback path on windows?
const v = std.os.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("TMP")) orelse return null;
return std.unicode.utf16leToUtf8Alloc(allocator, v) catch |e| {
log.warn("failed to convert temp dir path from windows string: {}", .{e});
return null;
};
}
if (std.os.getenv("TMPDIR")) |v| return v;
if (std.os.getenv("TMP")) |v| return v;
return "/tmp";
}
/// Free a path returned by tmpDir if it allocated memory.
/// This is a "no-op" for all platforms except windows.
pub fn freeTmpDir(allocator: std.mem.Allocator, dir: []const u8) void {
if (builtin.os.tag == .windows) {
allocator.free(dir);
}
}