fix: in bindings/ruby/test/jfk_reader/jfk_reader in jfk_reader.c (#3756)

* 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 <noreply@anthropic.com>

* 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 <noreply@anthropic.com>

* replacing ALLOC_N with rb_protect as ALLOC_N raises Ruby exceptions

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
OrbisAI Security 2026-05-25 11:49:23 +05:30 committed by GitHub
parent 0ccd896f5b
commit b3877e10c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 53 additions and 10 deletions

View 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");
fseek(file, 78, SEEK_SET);
fread(samples, sizeof(short), n_samples, file);
fclose(file);
for (int i = 0; i < n_samples; i++) {
data[i] = samples[i]/32768.0;
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(args.samples, sizeof(short), n_samples, file);
fclose(file);
for (int i = 0; i < n_samples; i++) {
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;
}