From 6531cf591b449cf2583bb4b3d7a6bd98ff58129b Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Wed, 5 Aug 2026 08:23:32 -0700 Subject: [PATCH] Stop write_skippable_frame reading past the end of its input dst_size is input_size + ZSTD_SKIPPABLEHEADERSIZE + skip_size, but input_data holds only input_size bytes, so rb_str_new(input_data, dst_size) reads (8 + skip_size) bytes past the end of the argument's buffer. The copied bytes never survive: ZSTD_writeSkippableFrame overwrites the frame at offset 0 and rb_str_resize then truncates the result to output_size. So the buffer only ever needed to be allocated, not initialised -- which is what rb_read_skippable_frame does a few lines below. --- ext/zstdruby/skippable_frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/zstdruby/skippable_frame.c b/ext/zstdruby/skippable_frame.c index 73534b8..d7cd457 100644 --- a/ext/zstdruby/skippable_frame.c +++ b/ext/zstdruby/skippable_frame.c @@ -23,7 +23,7 @@ static VALUE rb_write_skippable_frame(int argc, VALUE *argv, VALUE self) size_t skip_size = RSTRING_LEN(skip_value); size_t dst_size = input_size + ZSTD_SKIPPABLEHEADERSIZE + skip_size; - VALUE output = rb_str_new(input_data, dst_size); + VALUE output = rb_str_new(NULL, dst_size); char* output_data = RSTRING_PTR(output); size_t output_size = ZSTD_writeSkippableFrame((void*)output_data, dst_size, (const void*)skip_data, skip_size, magic_variant); if (ZSTD_isError(output_size)) {