From b000b4991e0d3ae033cc8d34cad30df667475c6b Mon Sep 17 00:00:00 2001 From: orbisai0security Date: Fri, 17 Apr 2026 11:28:40 +0000 Subject: [PATCH 1/4] fix: V-002 security vulnerability Automated security fix generated by Orbis Security AI --- bindings/ruby/test/jfk_reader/jfk_reader.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bindings/ruby/test/jfk_reader/jfk_reader.c b/bindings/ruby/test/jfk_reader/jfk_reader.c index 6657176e..dfb87dac 100644 --- a/bindings/ruby/test/jfk_reader/jfk_reader.c +++ b/bindings/ruby/test/jfk_reader/jfk_reader.c @@ -15,8 +15,15 @@ jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags) VALUE audio_path = rb_iv_get(obj, "audio_path"); const char *audio_path_str = StringValueCStr(audio_path); const int n_samples = 176000; - float *data = (float *)malloc(n_samples * sizeof(float)); - short *samples = (short *)malloc(n_samples * sizeof(short)); + float *data = (float *)calloc((size_t)n_samples, sizeof(float)); + if (data == NULL) { + return false; + } + short *samples = (short *)calloc((size_t)n_samples, sizeof(short)); + if (samples == NULL) { + free(data); + return false; + } FILE *file = fopen(audio_path_str, "rb"); fseek(file, 78, SEEK_SET); From f170d48777d8a2b45eb85c586e050db1160107b7 Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Sat, 18 Apr 2026 12:38:13 +0530 Subject: [PATCH 2/4] fix(ruby): use Ruby allocator macros in jfk_reader and fix memory leak - Replace calloc/free with ALLOC_N/xfree to match Ruby binding conventions (ALLOC_N handles overflow checking and raises NoMemoryError on failure) - Free temporary samples buffer after conversion loop (was leaked) - Add NULL check for fopen return value with rb_raise - Add comment clarifying n_samples is a compile-time constant Co-Authored-By: Claude Opus 4.6 --- bindings/ruby/test/jfk_reader/jfk_reader.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bindings/ruby/test/jfk_reader/jfk_reader.c b/bindings/ruby/test/jfk_reader/jfk_reader.c index dfb87dac..63b600a2 100644 --- a/bindings/ruby/test/jfk_reader/jfk_reader.c +++ b/bindings/ruby/test/jfk_reader/jfk_reader.c @@ -14,17 +14,16 @@ jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags) { VALUE audio_path = rb_iv_get(obj, "audio_path"); const char *audio_path_str = StringValueCStr(audio_path); + // n_samples is a fixed constant (not derived from user input). const int n_samples = 176000; - float *data = (float *)calloc((size_t)n_samples, sizeof(float)); - if (data == NULL) { - return false; - } - short *samples = (short *)calloc((size_t)n_samples, sizeof(short)); - if (samples == NULL) { - free(data); - return false; - } + float *data = ALLOC_N(float, n_samples); + short *samples = ALLOC_N(short, n_samples); FILE *file = fopen(audio_path_str, "rb"); + if (file == NULL) { + xfree(samples); + xfree(data); + rb_raise(rb_eIOError, "failed to open audio file"); + } fseek(file, 78, SEEK_SET); fread(samples, sizeof(short), n_samples, file); @@ -32,6 +31,7 @@ jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags) for (int i = 0; i < n_samples; i++) { data[i] = samples[i]/32768.0; } + xfree(samples); view->obj = obj; view->data = (void *)data; From 0723001fc590cc64ddddb8099be335c33cab12ec Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Mon, 20 Apr 2026 09:09:19 +0530 Subject: [PATCH 3/4] fix(ruby): return false instead of rb_raise in memory_view callback rb_memory_view_get_func_t callbacks should communicate errors via return value (false), not exceptions. rb_memory_view_get has no exception-handling wrapper around get_func calls. Co-Authored-By: Claude Opus 4.6 --- bindings/ruby/test/jfk_reader/jfk_reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/ruby/test/jfk_reader/jfk_reader.c b/bindings/ruby/test/jfk_reader/jfk_reader.c index 63b600a2..5843f0be 100644 --- a/bindings/ruby/test/jfk_reader/jfk_reader.c +++ b/bindings/ruby/test/jfk_reader/jfk_reader.c @@ -22,7 +22,7 @@ jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags) if (file == NULL) { xfree(samples); xfree(data); - rb_raise(rb_eIOError, "failed to open audio file"); + return false; } fseek(file, 78, SEEK_SET); From 2f3f4471cb160be8ed1101b9ddd81cedf02a1ce3 Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Wed, 22 Apr 2026 06:53:19 +0530 Subject: [PATCH 4/4] replacing ALLOC_N with rb_protect as ALLOC_N raises Ruby exceptions --- bindings/ruby/test/jfk_reader/jfk_reader.c | 56 ++++++++++++++++++---- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/bindings/ruby/test/jfk_reader/jfk_reader.c b/bindings/ruby/test/jfk_reader/jfk_reader.c index 5843f0be..62207aaa 100644 --- a/bindings/ruby/test/jfk_reader/jfk_reader.c +++ b/bindings/ruby/test/jfk_reader/jfk_reader.c @@ -2,6 +2,24 @@ #include #include +typedef struct { + VALUE audio_path; + int n_samples; + const char *audio_path_str; + float *data; + short *samples; +} jfk_alloc_args; + +static VALUE +jfk_reader_alloc_resources(VALUE arg) +{ + jfk_alloc_args *a = (jfk_alloc_args *)arg; + a->audio_path_str = StringValueCStr(a->audio_path); + a->data = ALLOC_N(float, a->n_samples); + a->samples = ALLOC_N(short, a->n_samples); + return Qnil; +} + static VALUE jfk_reader_initialize(VALUE self, VALUE audio_path) { @@ -13,28 +31,42 @@ static bool jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags) { VALUE audio_path = rb_iv_get(obj, "audio_path"); - const char *audio_path_str = StringValueCStr(audio_path); // n_samples is a fixed constant (not derived from user input). const int n_samples = 176000; - float *data = ALLOC_N(float, n_samples); - short *samples = ALLOC_N(short, n_samples); - FILE *file = fopen(audio_path_str, "rb"); + + jfk_alloc_args args = { + .audio_path = audio_path, + .n_samples = n_samples, + .audio_path_str = NULL, + .data = NULL, + .samples = NULL, + }; + + int state; + rb_protect(jfk_reader_alloc_resources, (VALUE)&args, &state); + if (state) { + if (args.samples) xfree(args.samples); + if (args.data) xfree(args.data); + return false; + } + + FILE *file = fopen(args.audio_path_str, "rb"); if (file == NULL) { - xfree(samples); - xfree(data); + xfree(args.samples); + xfree(args.data); return false; } fseek(file, 78, SEEK_SET); - fread(samples, sizeof(short), n_samples, file); + fread(args.samples, sizeof(short), n_samples, file); fclose(file); for (int i = 0; i < n_samples; i++) { - data[i] = samples[i]/32768.0; + args.data[i] = args.samples[i] / 32768.0; } - xfree(samples); + xfree(args.samples); view->obj = obj; - view->data = (void *)data; + view->data = (void *)args.data; view->byte_size = sizeof(float) * n_samples; view->readonly = true; view->format = "f"; @@ -52,6 +84,10 @@ jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags) static bool jfk_reader_release_memory_view(const VALUE obj, rb_memory_view_t *view) { + if (view->data) { + xfree(view->data); + view->data = NULL; + } return true; }