b0070dd0
Harden FrameLoop per code-quality review
a73x 2026-04-16 11:03
- commitRender: convert canRender precondition from std.debug.assert (compiled out in ReleaseFast) to a runtime error.CannotRender, so caller logic bugs are observable in release builds. - waitForWork: propagate only .revents back to the caller's pollfd slice; .events and .fd are caller-owned and should be preserved. - waitForWork doc: make the 8-extra cap rationale explicit on the public API. Follow-up to dec56ed.
diff --git a/src/frame_loop.zig b/src/frame_loop.zig index d3e84c3..640872b 100644 --- a/src/frame_loop.zig +++ b/src/frame_loop.zig @@ -64,7 +64,7 @@ pub const FrameLoop = struct { } pub fn commitRender(self: *FrameLoop) !void { std.debug.assert(self.canRender()); if (!self.canRender()) return error.CannotRender; if (self.pending_token) |t| self.ops.destroyCallbackFn(self.ops.ctx, t); self.pending_token = try self.ops.requestFrameFn(self.ops.ctx, self); self.armed = false; @@ -95,6 +95,11 @@ pub const FrameLoop = struct { /// Blocks on wl_fd + extra pollfds with `timeout_ms`, then reads + dispatches /// any pending Wayland events. Safe to call in any state. /// /// `extra.len` must not exceed 8. waystty's production callers never poll /// more than wl_fd + one extra fd (pty); the cap of 8 is a 4x margin and /// keeps the internal pollfd array stack-allocated. Increase requires a /// review of the stack frame size in this function. pub fn waitForWork( self: *FrameLoop, extra: []std.posix.pollfd, @@ -113,8 +118,9 @@ pub const FrameLoop = struct { _ = std.posix.poll(all[0..total], timeout_ms) catch {}; // Propagate revents back into caller's extra slice. for (extra, 0..) |*fd, i| fd.* = all[i + 1]; // Propagate only revents back into caller's extra slice; events/fd are // caller-owned and must be preserved across calls. for (extra, 0..) |*fd, i| fd.revents = all[i + 1].revents; if (all[0].revents & std.posix.POLL.IN != 0) { if (self.ops.prepareReadFn(self.ops.ctx)) {