From 38ef2c03f9e17101ddc230d266841ca52903f5d6 Mon Sep 17 00:00:00 2001 From: foxnne Date: Sat, 17 Oct 2026 19:48:36 -0500 Subject: [PATCH] zig: what 0.16 needed goes with the move The tape reader's Endless input, which kept 0.16's inflate off a bug in a stream cut short, is gone: 0.17's inflate checks the bits it has before tossing them, so a fixed reader does, and a cut-short stream reads as corrupt. The readme and the plugin guide say Zig 0.17.0. Co-Authored-By: Claude Opus 5.5 --- docs/PLUGINS.md | 4 ++-- readme.md | 2 +- sdk/tape/binary.zig | 33 +++------------------------------ 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/docs/PLUGINS.md b/docs/PLUGINS.md index abe6e55cd..a6550b010 100644 --- a/docs/PLUGINS.md +++ b/docs/PLUGINS.md @@ -163,7 +163,7 @@ which produces: .{ .name = .my_plugin, .version = "0.1.0", - .minimum_zig_version = "0.16.0", + .minimum_zig_version = "0.17.0", .paths = .{ "build.zig", "build.zig.zon", "plugin.zig", "plugin.zig.zon", "src" }, .fingerprint = 0x0000000000000000, // zig fills this in on first `zig build` .dependencies = .{ @@ -1624,7 +1624,7 @@ jobs: permissions: contents: write with: - zig-version: "0.16.0" + zig-version: "0.17.0" ``` Bump the `sdk-v*` tag your `build.zig.zon` pins when you want a new SDK; the next tag's manifest picks up diff --git a/readme.md b/readme.md index ff4f468f7..e6c703421 100644 --- a/readme.md +++ b/readme.md @@ -30,7 +30,7 @@ By default, when you install fizzy, only builtin plugins are included. This give ## Compilation - [Linux] Ensure `gtk+3-devel` or similar is installed (for native file dialogs). -- Install zig 0.16.0. +- Install zig 0.17.0. - Clone fizzy. - Build. - ```git clone https://github.com/fizzyedit/fizzy.git``` diff --git a/sdk/tape/binary.zig b/sdk/tape/binary.zig index fff8e7ada..8fe3610ec 100644 --- a/sdk/tape/binary.zig +++ b/sdk/tape/binary.zig @@ -419,13 +419,12 @@ pub fn read(gpa: std.mem.Allocator, bytes: []const u8, check: Tape.Check) ReadEr if (tape_version < 3) return error.Corrupt; const len = try pre.int(u32); if (len > max_inflated) return error.Corrupt; - var in_buffer: [4096]u8 = undefined; - var in: Endless = .init(bytes[prefix_size + 4 ..], &in_buffer); + var in: std.Io.Reader = .fixed(bytes[prefix_size + 4 ..]); const window = try gpa.alloc(u8, flate.max_window_len); defer gpa.free(window); - var d: flate.Decompress = .init(&in.reader, .zlib, window); + var d: flate.Decompress = .init(&in, .zlib, window); // One byte more than it should come to, so a stream that runs on is caught; a stream cut - // short runs on into the zeros, or stops early, or fails its checksum. + // short fails to read, or stops early, or fails its checksum. const inflated = d.reader.allocRemaining(a, .limited(@as(usize, len) + 1)) catch |err| return switch (err) { error.OutOfMemory => error.OutOfMemory, error.ReadFailed, error.StreamTooLong => error.Corrupt, @@ -568,32 +567,6 @@ pub fn read(gpa: std.mem.Allocator, bytes: []const u8, check: Tape.Check) ReadEr return .{ .arena = arena, .tape = tape }; } -/// A deflated stream's bytes, then zeros without end. std's inflate (0.16) misreads a stream that -/// ends inside its last four bytes (`tossBitsShort` adds the bits it has used where it should take -/// them away) and asserts past the end of its input — a crash on a tape cut short. Never letting -/// its input end keeps it off that path; the inflated length, known from the header, bounds what a -/// stream cut short can run on into. ZIG017: fixed in 0.17's inflate, so this goes with the move; -/// 0.17 still leaves the checksum unchecked, so `read`'s Adler-32 check stays. -const Endless = struct { - rest: []const u8, - reader: std.Io.Reader, - - fn init(bytes: []const u8, buffer: []u8) Endless { - return .{ .rest = bytes, .reader = .{ .vtable = &.{ .stream = stream }, .buffer = buffer, .seek = 0, .end = 0 } }; - } - - fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { - const self: *Endless = @alignCast(@fieldParentPtr("reader", r)); - const dest = limit.slice(try w.writableSliceGreedy(1)); - const n = @min(dest.len, self.rest.len); - @memcpy(dest[0..n], self.rest[0..n]); - @memset(dest[n..], 0); - self.rest = self.rest[n..]; - w.advance(dest.len); - return dest.len; - } -}; - /// `n` records of `size` bytes, or `error.Corrupt` when that is more than a tape could hold. fn sizeOf(n: usize, size: usize) ReadError!usize { return std.math.mul(usize, n, size) catch error.Corrupt;