mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 01:06:08 +03:00
core: protect against crashes and hangs when themes are not files (#5632)
If a theme was not a file or a directory you could get a crash or a hang (depending on platform) if the theme references a directory. This patch also prevents attempts to load from other non-file sources. Fixes: #5596
This commit is contained in:
@ -8,6 +8,8 @@ const internal_os = @import("../os/main.zig");
|
|||||||
const Diagnostic = diags.Diagnostic;
|
const Diagnostic = diags.Diagnostic;
|
||||||
const DiagnosticList = diags.DiagnosticList;
|
const DiagnosticList = diags.DiagnosticList;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.cli);
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - Only `--long=value` format is accepted. Do we want to allow
|
// - Only `--long=value` format is accepted. Do we want to allow
|
||||||
// `--long value`? Not currently allowed.
|
// `--long value`? Not currently allowed.
|
||||||
@ -1258,9 +1260,11 @@ pub fn LineIterator(comptime ReaderType: type) type {
|
|||||||
const buf = buf: {
|
const buf = buf: {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Read the full line
|
// Read the full line
|
||||||
var entry = self.r.readUntilDelimiterOrEof(self.entry[2..], '\n') catch {
|
var entry = self.r.readUntilDelimiterOrEof(self.entry[2..], '\n') catch |err| switch (err) {
|
||||||
// TODO: handle errors
|
inline else => |e| {
|
||||||
unreachable;
|
log.warn("cannot read from \"{s}\": {}", .{ self.filepath, e });
|
||||||
|
return null;
|
||||||
|
},
|
||||||
} orelse return null;
|
} orelse return null;
|
||||||
|
|
||||||
// Increment our line counter
|
// Increment our line counter
|
||||||
|
@ -104,6 +104,10 @@ pub const LocationIterator = struct {
|
|||||||
/// Due to the way allocations are handled, an Arena allocator (or another
|
/// Due to the way allocations are handled, an Arena allocator (or another
|
||||||
/// similar allocator implementation) should be used. It may not be safe to
|
/// similar allocator implementation) should be used. It may not be safe to
|
||||||
/// free the returned allocations.
|
/// free the returned allocations.
|
||||||
|
///
|
||||||
|
/// This will never return anything other than a handle to a regular file. If
|
||||||
|
/// the theme resolves to something other than a regular file a diagnostic entry
|
||||||
|
/// will be added to the list and null will be returned.
|
||||||
pub fn open(
|
pub fn open(
|
||||||
arena_alloc: Allocator,
|
arena_alloc: Allocator,
|
||||||
theme: []const u8,
|
theme: []const u8,
|
||||||
@ -119,6 +123,29 @@ pub fn open(
|
|||||||
theme,
|
theme,
|
||||||
diags,
|
diags,
|
||||||
) orelse return null;
|
) orelse return null;
|
||||||
|
const stat = file.stat() catch |err| {
|
||||||
|
try diags.append(arena_alloc, .{
|
||||||
|
.message = try std.fmt.allocPrintZ(
|
||||||
|
arena_alloc,
|
||||||
|
"not reading theme from \"{s}\": {}",
|
||||||
|
.{ theme, err },
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
switch (stat.kind) {
|
||||||
|
.file => {},
|
||||||
|
else => {
|
||||||
|
try diags.append(arena_alloc, .{
|
||||||
|
.message = try std.fmt.allocPrintZ(
|
||||||
|
arena_alloc,
|
||||||
|
"not reading theme from \"{s}\": it is a {s}",
|
||||||
|
.{ theme, @tagName(stat.kind) },
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
return .{ .path = theme, .file = file };
|
return .{ .path = theme, .file = file };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,9 +167,34 @@ pub fn open(
|
|||||||
const cwd = std.fs.cwd();
|
const cwd = std.fs.cwd();
|
||||||
while (try it.next()) |loc| {
|
while (try it.next()) |loc| {
|
||||||
const path = try std.fs.path.join(arena_alloc, &.{ loc.dir, theme });
|
const path = try std.fs.path.join(arena_alloc, &.{ loc.dir, theme });
|
||||||
if (cwd.openFile(path, .{})) |file| return .{
|
if (cwd.openFile(path, .{})) |file| {
|
||||||
.path = path,
|
const stat = file.stat() catch |err| {
|
||||||
.file = file,
|
try diags.append(arena_alloc, .{
|
||||||
|
.message = try std.fmt.allocPrintZ(
|
||||||
|
arena_alloc,
|
||||||
|
"not reading theme from \"{s}\": {}",
|
||||||
|
.{ theme, err },
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
switch (stat.kind) {
|
||||||
|
.file => {},
|
||||||
|
else => {
|
||||||
|
try diags.append(arena_alloc, .{
|
||||||
|
.message = try std.fmt.allocPrintZ(
|
||||||
|
arena_alloc,
|
||||||
|
"not reading theme from \"{s}\": it is a {s}",
|
||||||
|
.{ theme, @tagName(stat.kind) },
|
||||||
|
),
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return .{
|
||||||
|
.path = path,
|
||||||
|
.file = file,
|
||||||
|
};
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
// Not an error, just continue to the next location.
|
// Not an error, just continue to the next location.
|
||||||
error.FileNotFound => {},
|
error.FileNotFound => {},
|
||||||
|
Reference in New Issue
Block a user