From 3b8141fbd8e2f5770809d3df2fe0077849866dde Mon Sep 17 00:00:00 2001 From: Johannes Zillmann Date: Wed, 2 Sep 2026 10:45:08 -0600 Subject: [PATCH] os/open: consume the newline when draining opener stderr takeDelimiterExclusive never consumes the delimiter: it tosses only the exclusive length, so the '\n' stays buffered. Once the spawned opener writes a single line to stderr, every subsequent call returns an empty slice without advancing the stream, and openThread's loop spins forever - one pinned core per affected open(), logging empty "open stderr=" warnings at tens of thousands of messages per second for the lifetime of the process. The thread also never reaches exe.wait(), so the child is never reaped. Read inclusively instead (which does consume the delimiter) and trim the '\n' for logging. Repro: open a link whose handler writes to stderr, e.g. an OSC 8 link with an unknown scheme; watch a core disappear and the unified log flood with "os-open: open stderr=". See discussion #14100. --- src/os/open.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/os/open.zig b/src/os/open.zig index bc09518e6..e7574618e 100644 --- a/src/os/open.zig +++ b/src/os/open.zig @@ -86,7 +86,11 @@ fn openThread(io: std.Io, exe_: std.process.Child) void { var stream = stderr.readerStreaming(io, &buffer); const reader = &stream.interface; while (true) { - const line = reader.takeDelimiterExclusive('\n') catch |outer| switch (outer) { + // Read inclusively so the delimiter is consumed: + // takeDelimiterExclusive leaves the '\n' buffered, so once the + // child writes a line this loop would receive an empty slice + // forever, pinning a core and spamming empty warnings. + const line = reader.takeDelimiterInclusive('\n') catch |outer| switch (outer) { error.EndOfStream => break, error.ReadFailed => break, error.StreamTooLong => reader.take(buffer.len) catch |inner| switch (inner) { @@ -94,7 +98,7 @@ fn openThread(io: std.Io, exe_: std.process.Child) void { error.EndOfStream => break, }, }; - log.warn("open stderr={s}", .{line}); + log.warn("open stderr={s}", .{std.mem.trimEnd(u8, line, "\n")}); } } _ = exe.wait(io) catch {};