summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/9p_io.zig45
1 files changed, 40 insertions, 5 deletions
diff --git a/src/9p_io.zig b/src/9p_io.zig
index 78ff5d59..d1b2099c 100644
--- a/src/9p_io.zig
+++ b/src/9p_io.zig
@@ -851,6 +851,16 @@ pub fn listen(io: std.Io, gpa: std.mem.Allocator, core: *pardes.Pardes, named: [
return null;
};
if (!ensureSocketDir(dir)) return null;
+ const entry_name = if (named.len != 0) named else fallback;
+ // Checked before anything is made: the turn's hooks point at the
+ // listener from here on, and a path too long for sun_path used to free
+ // it with them still set, so the editor's next rest called into freed
+ // memory.
+ var path_check: [sun_path_len]u8 = undefined;
+ if (socketPath(&path_check, dir, entry_name) == null) {
+ log.warn("no socket for {s}: the path is too long for a unix socket", .{entry_name});
+ return null;
+ }
const l = gpa.create(Listener) catch return null;
l.* = .{ .io = io, .core = core };
pardes.turn.start(io);
@@ -863,11 +873,7 @@ pub fn listen(io: std.Io, gpa: std.mem.Allocator, core: *pardes.Pardes, named: [
.handler = .{ .ctx = l, .serve = Listener.onServe, .opened = Listener.onOpened, .refused = Listener.onRefused },
.greet_timeout_ms = Listener.greet_deadline_ms,
});
- const entry_name = if (named.len != 0) named else fallback;
- const p = socketPath(&l.path_buf, dir, entry_name) orelse {
- gpa.destroy(l);
- return null;
- };
+ const p = socketPath(&l.path_buf, dir, entry_name).?;
_ = l.runner.listen(.{ .unix = p }, max_conns) catch |err| retry: {
const existing = @import("fs.zig").statPath(io, p, .{ .follow_symlinks = false }) catch null;
if (err != error.AddressInUse or existing == null or existing.?.kind != .unix_domain_socket or alive(p)) {
@@ -1261,6 +1267,35 @@ test "TCP addresses are numeric and normalize mapped IPv4" {
extern "c" fn mkdtemp(template: [*:0]u8) ?[*:0]u8;
extern "c" fn rmdir(path: [*:0]const u8) c_int;
+test "a socket path too long for sun_path is no listener, and leaves the editor's turn as it was" {
+ if (comptime !supported) return error.SkipZigTest;
+ const p = try pardes.Pardes.init(testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ var directory: [64:0]u8 = undefined;
+ _ = try std.fmt.bufPrintSentinel(&directory, "/tmp/pardes-long-XXXXXX", .{}, 0);
+ if (mkdtemp(&directory) == null) return error.TempDirectoryFailed;
+ const dir = std.mem.span(@as([*:0]const u8, &directory));
+ defer _ = rmdir(&directory);
+ // A name that fits: the directory is one a listener takes.
+ var fits: [sun_path_len]u8 = undefined;
+ try testing.expect(socketPath(&fits, dir, "short") != null);
+ const old = libc.getenv("XDG_RUNTIME_DIR");
+ var old_buf: [4096]u8 = undefined;
+ const old_copy = if (old) |o| try std.fmt.bufPrintSentinel(&old_buf, "{s}", .{std.mem.span(o)}, 0) else null;
+ var z: [4096]u8 = undefined;
+ _ = setenv("XDG_RUNTIME_DIR", try std.fmt.bufPrintSentinel(&z, "{s}", .{dir}, 0), 1);
+ defer if (old_copy) |o| {
+ _ = setenv("XDG_RUNTIME_DIR", o, 1);
+ } else {
+ _ = unsetenv("XDG_RUNTIME_DIR");
+ };
+ const long = "n" ** 120;
+ try testing.expect(listen(testing.io, testing.allocator, p, long, "", null, null) == null);
+ try testing.expect(pardes.turn.answer_held == null);
+ try testing.expect(pardes.turn.wake_parked == null);
+ try testing.expect(pardes.turn.io == null);
+}
+
test "a listening editor posts itself into the 9P registry and unposts on stop" {
if (comptime !supported) return error.SkipZigTest;
const gpa = testing.allocator;