You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
libghostty-vt: decode png hook should support a cap on bytes returned #12163
Does the caller supplying a FixedBufferAllocator solve this problem? That way the caller has complete control over the allocation hot path, and can ensure it is preheated with enough capacity to fit their needs. The problem then is that the wuffs fn decode uses one allocator for both scratch lifetimes and result lifetimes. so instead of providing a cap config or similar, the memory lifetimes just need to be separated instead.
The function would change simply:
/// Decode a PNG image.pubfndecode(result: Allocator, scratch: Allocator, data: []constu8) Error!ImageData {
// Work around some weirdness in WUFFS/Zig, there are some structs that// are defined as "extern" by the Zig compiler which means that Zig won't// allocate them on the stack at compile time. WUFFS has functions for// dynamically allocating these structs but they use the C malloc/free. This// gets around that by using the Zig allocator to allocate enough memory for// the struct and then casts it to the appropriate pointer.constdecoder_buf=tryresult.alloc(u8, c.sizeof__wuffs_png__decoder());
deferresult.free(decoder_buf);
constdecoder: ?*c.wuffs_png__decoder=@ptrCast(decoder_buf);
{
conststatus=c.wuffs_png__decoder__initialize(
decoder,
c.sizeof__wuffs_png__decoder(),
c.WUFFS_VERSION,
0,
);
trycheck(log, &status);
}
varsource_buffer: c.wuffs_base__io_buffer= .{
.data= .{ .ptr=@ptrCast(@constCast(data.ptr)), .len=data.len },
.meta= .{
.wi=data.len,
.ri=0,
.pos=0,
.closed=true,
},
};
varimage_config: c.wuffs_base__image_config=undefined;
{
conststatus=c.wuffs_png__decoder__decode_image_config(
decoder,
&image_config,
&source_buffer,
);
trycheck(log, &status);
}
constwidth=c.wuffs_base__pixel_config__width(&image_config.pixcfg);
constheight=c.wuffs_base__pixel_config__height(&image_config.pixcfg);
c.wuffs_base__pixel_config__set(
&image_config.pixcfg,
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL,
c.WUFFS_BASE__PIXEL_SUBSAMPLING__NONE,
width,
height,
);
constsize: usize=trymul(
usize,
trymul(usize, width, height),
@sizeOf(c.wuffs_base__color_u32_argb_premul),
);
if (size>maximum_image_size) {
log.warn("image size {d} is larger than the maximum allowed ({d})", .{ size, maximum_image_size });
returnerror.Overflow;
}
constdestination=tryresult.alloc(
u8,
size,
);
errdeferresult.free(destination);
// NOTE: this comment is now redundant, as the allocator expresses the intent directly// temporary buffer for intermediate processing of imageconstwork_buffer=tryscratch.alloc(
u8,
// The type of this is a u64 on all systems but our allocator// uses a usize which is a u32 on 32-bit systems.std.math.cast(
usize,
c.wuffs_png__decoder__workbuf_len(decoder).max_incl,
) orelsereturnerror.OutOfMemory,
);
deferscratch.free(work_buffer);
constwork_slice=c.wuffs_base__make_slice_u8(
work_buffer.ptr,
work_buffer.len,
);
varpixel_buffer: c.wuffs_base__pixel_buffer=undefined;
{
conststatus=c.wuffs_base__pixel_buffer__set_from_slice(
&pixel_buffer,
&image_config.pixcfg,
c.wuffs_base__make_slice_u8(destination.ptr, destination.len),
);
trycheck(log, &status);
}
{
conststatus=c.wuffs_png__decoder__decode_frame(
decoder,
&pixel_buffer,
&source_buffer,
c.WUFFS_BASE__PIXEL_BLEND__SRC,
work_slice,
null,
);
trycheck(log, &status);
}
return .{
.width=width,
.height=height,
.data=destination,
};
}
Activity
mitchellh commentedon Apr 7, 2026
In general, we should consider this pattern anywhere we get allocated data returned, fyi.
mdm5995 commentedon Apr 11, 2026
Does the caller supplying a FixedBufferAllocator solve this problem? That way the caller has complete control over the allocation hot path, and can ensure it is preheated with enough capacity to fit their needs. The problem then is that the wuffs
fn decodeuses one allocator for both scratch lifetimes and result lifetimes. so instead of providing a cap config or similar, the memory lifetimes just need to be separated instead.The function would change simply:
libghostty-vt: let the png decode hook report extra allocated bytes
libghostty-vt: let the png decode hook report extra allocated bytes
libghostty-vt: let the png decode hook report extra allocated bytes