From 92b4fa1085c5202fcb969f7effc439999f3b2d55 Mon Sep 17 00:00:00 2001 From: brookjeynes Date: Wed, 7 Jan 2026 08:28:30 +1000 Subject: [PATCH] fix: update zigimg + libvaxis to fix image segfault during image processing --- build.zig.zon | 12 ++++++--- src/app.zig | 9 +++++-- src/drawer.zig | 66 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 0b8ffe7..6a2fb7a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,12 +2,13 @@ .name = .jido, .fingerprint = 0xee45eabe36cafb57, .version = "1.3.0", - .minimum_zig_version = "0.14.0", + .minimum_zig_version = "0.15.2", .dependencies = .{ + // Replace with rockorager/libvaxis once https://github.com/rockorager/libvaxis/pull/293 is merged .vaxis = .{ - .url = "git+https://github.com/rockorager/libvaxis.git#75035b169e91a51c233f3742161f8eb8eafca659", - .hash = "vaxis-0.5.1-BWNV_IE-CQBYmSf_boEKUyv6den0Gmj5LksxvdCx2pBL", + .url = "git+https://github.com/rob9315/libvaxis.git#8d04cffd9137b4a8c56b356de98b32023ae752f3", + .hash = "vaxis-0.5.1-BWNV_OA-CQDeFBHIx9ryyASogr2GE3FsAm-l5Ii5-HZT", }, .fuzzig = .{ .url = "git+https://github.com/fjebaker/fuzzig#4251fe4230d38e721514394a485db62ee1667ff3", @@ -22,6 +23,11 @@ .url = "https://github.com/BrookJeynes/zuid/archive/refs/heads/bj/2025-12-31/feat/0.15.1.tar.gz", .hash = "zuid-3.0.0-l7aPyUlXAAAk9BLSDm2roA3i78Sy6_GvQI4hwe0PHI_m", }, + // Replace with zigimg/zigimg once https://github.com/zigimg/zigimg/pull/305 is merged + .zigimg = .{ + .url = "git+https://github.com/brookjeynes/zigimg.git#9714df09f76891323c7fdbbbf23a17b79024fffb", + .hash = "zigimg-0.1.0-8_eo2j4mFwCU7tWnqvkYtzqe-OPRn_bxEql_IJhW85LT", + }, }, .paths = .{ diff --git a/src/app.zig b/src/app.zig index ffad8b9..28781eb 100644 --- a/src/app.zig +++ b/src/app.zig @@ -79,9 +79,11 @@ pub const Event = union(enum) { }; pub const Image = struct { + const buf_size = (1024 * 1024) * 5; // 5mb const Status = enum { ready, processing, + failed, }; ///Only use on first transmission. Subsequent draws should use @@ -91,7 +93,10 @@ pub const Image = struct { path: ?[]const u8 = null, status: Status = .processing, - pub fn deinit(self: @This(), alloc: std.mem.Allocator) void { + pub fn deinit(self: @This(), alloc: std.mem.Allocator, vx: vaxis.Vaxis, tty: *vaxis.Tty) void { + if (self.image) |image| { + vx.freeImage(tty.writer(), image.id); + } if (self.data) |data| { var d = data; d.deinit(alloc); @@ -197,7 +202,7 @@ pub fn deinit(self: *App) void { var image_iter = self.images.cache.iterator(); while (image_iter.next()) |img| { - img.value_ptr.deinit(self.alloc); + img.value_ptr.deinit(self.alloc, self.vx, &self.tty); } self.images.cache.deinit(); } diff --git a/src/drawer.zig b/src/drawer.zig index 31acc22..664d254 100644 --- a/src/drawer.zig +++ b/src/drawer.zig @@ -208,6 +208,13 @@ fn drawFilePreview( break :file; } + if (cache_entry.status == .failed) { + _ = preview_win.print(&.{ + .{ .text = "Failed to process image." }, + }, .{}); + break :file; + } + if (cache_entry.image) |img| { img.draw(preview_win, .{ .scale = .contain }) catch |err| { const message = try std.fmt.allocPrint(app.alloc, "Failed to draw image to screen - {}.", .{err}); @@ -224,8 +231,14 @@ fn drawFilePreview( } else { if (cache_entry.data == null) { const path = try app.alloc.dupe(u8, self.current_item_path); - var buffer: [1024]u8 = undefined; - processImage(app, path, &buffer) catch break :unsupported; + processImage(app, path) catch { + app.alloc.free(path); + break :unsupported; + }; + _ = preview_win.print(&.{ + .{ .text = "Image still processing." }, + }, .{}); + break :file; } if (app.vx.transmitImage(app.alloc, app.tty.writer(), &cache_entry.data.?, .rgba)) |img| { @@ -241,7 +254,10 @@ fn drawFilePreview( break :file; }; cache_entry.image = img; - cache_entry.data.?.deinit(app.alloc); + if (cache_entry.data) |data| { + var d = data; + d.deinit(app.alloc); + } cache_entry.data = null; } else |_| { break :unsupported; @@ -250,9 +266,15 @@ fn drawFilePreview( break :file; } else { + _ = preview_win.print(&.{ + .{ .text = "Processing image." }, + }, .{}); + const path = try app.alloc.dupe(u8, self.current_item_path); - var buffer: [1024]u8 = undefined; - processImage(app, path, &buffer) catch break :unsupported; + processImage(app, path) catch { + app.alloc.free(path); + break :unsupported; + }; } break :file; @@ -630,7 +652,7 @@ fn drawNotification( }, .{ .wrap = .word }); } -fn processImage(app: *App, path: []const u8, buffer: *[1024]u8) error{ Unsupported, OutOfMemory }!void { +fn processImage(app: *App, path: []const u8) error{ Unsupported, OutOfMemory }!void { app.images.cache.put(path, .{ .path = path, .status = .processing }) catch { const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to add image to cache.", .{path}); defer app.alloc.free(message); @@ -642,18 +664,38 @@ fn processImage(app: *App, path: []const u8, buffer: *[1024]u8) error{ Unsupport const load_img_thread = std.Thread.spawn(.{}, loadImage, .{ app, path, - buffer, - }) catch return error.Unsupported; + }) catch { + app.images.mutex.lock(); + if (app.images.cache.getPtr(path)) |entry| { + entry.status = .failed; + } + app.images.mutex.unlock(); + + const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to spawn processing thread.", .{path}); + defer app.alloc.free(message); + app.notification.write(message, .err) catch {}; + if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; + + return error.Unsupported; + }; load_img_thread.detach(); } -fn loadImage(app: *App, path: []const u8, buffer: *[1024]u8) error{ Unsupported, OutOfMemory }!void { - const data = vaxis.zigimg.Image.fromFilePath(app.alloc, path, buffer) catch { +fn loadImage(app: *App, path: []const u8) error{OutOfMemory}!void { + var buf: [(1024 * 1024) * 5]u8 = undefined; + const data = vaxis.zigimg.Image.fromFilePath(app.alloc, path, &buf) catch { + app.images.mutex.lock(); + if (app.images.cache.getPtr(path)) |entry| { + entry.status = .failed; + } + app.images.mutex.unlock(); + const message = try std.fmt.allocPrint(app.alloc, "Failed to load image '{s}' - error occurred while attempting to read image from path.", .{path}); defer app.alloc.free(message); app.notification.write(message, .err) catch {}; if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; - return error.Unsupported; + + return; }; app.images.mutex.lock(); @@ -665,7 +707,7 @@ fn loadImage(app: *App, path: []const u8, buffer: *[1024]u8) error{ Unsupported, defer app.alloc.free(message); app.notification.write(message, .err) catch {}; if (app.file_logger) |file_logger| file_logger.write(message, .err) catch {}; - return error.Unsupported; + return; } app.images.mutex.unlock(); -- 2.51.2