]> git.djapps.eu Git - pkg/ggml/sources/whisper.cpp/commitdiff
fix: in bindings/ruby/test/jfk_reader/jfk_reader in jfk_reader.c (#3756)
authorOrbisAI Security <redacted>
Mon, 25 May 2026 06:19:23 +0000 (11:49 +0530)
committerGitHub <redacted>
Mon, 25 May 2026 06:19:23 +0000 (08:19 +0200)
* fix: V-002 security vulnerability

Automated security fix generated by Orbis Security AI

* 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 <redacted>
* 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 <redacted>
* replacing ALLOC_N with rb_protect as ALLOC_N raises Ruby exceptions

---------

Co-authored-by: Claude Opus 4.6 <redacted>
bindings/ruby/test/jfk_reader/jfk_reader.c

index 6657176e767578de72963b917342998156a8e438..62207aaa4113e14e38b5beddd7cceef8a2e64c42 100644 (file)
@@ -2,6 +2,24 @@
 #include <ruby/memory_view.h>
 #include <ruby/encoding.h>
 
+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,21 +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 = (float *)malloc(n_samples * sizeof(float));
-  short *samples = (short *)malloc(n_samples * sizeof(short));
-  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(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(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";
@@ -45,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;
 }