Skip to content

Commit b3877e1

Browse files
OrbisAI Securityclaude
andauthored
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>
1 parent 0ccd896 commit b3877e1

1 file changed

Lines changed: 50 additions & 7 deletions

File tree

bindings/ruby/test/jfk_reader/jfk_reader.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22
#include <ruby/memory_view.h>
33
#include <ruby/encoding.h>
44

5+
typedef struct {
6+
VALUE audio_path;
7+
int n_samples;
8+
const char *audio_path_str;
9+
float *data;
10+
short *samples;
11+
} jfk_alloc_args;
12+
13+
static VALUE
14+
jfk_reader_alloc_resources(VALUE arg)
15+
{
16+
jfk_alloc_args *a = (jfk_alloc_args *)arg;
17+
a->audio_path_str = StringValueCStr(a->audio_path);
18+
a->data = ALLOC_N(float, a->n_samples);
19+
a->samples = ALLOC_N(short, a->n_samples);
20+
return Qnil;
21+
}
22+
523
static VALUE
624
jfk_reader_initialize(VALUE self, VALUE audio_path)
725
{
@@ -13,21 +31,42 @@ static bool
1331
jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags)
1432
{
1533
VALUE audio_path = rb_iv_get(obj, "audio_path");
16-
const char *audio_path_str = StringValueCStr(audio_path);
34+
// n_samples is a fixed constant (not derived from user input).
1735
const int n_samples = 176000;
18-
float *data = (float *)malloc(n_samples * sizeof(float));
19-
short *samples = (short *)malloc(n_samples * sizeof(short));
20-
FILE *file = fopen(audio_path_str, "rb");
36+
37+
jfk_alloc_args args = {
38+
.audio_path = audio_path,
39+
.n_samples = n_samples,
40+
.audio_path_str = NULL,
41+
.data = NULL,
42+
.samples = NULL,
43+
};
44+
45+
int state;
46+
rb_protect(jfk_reader_alloc_resources, (VALUE)&args, &state);
47+
if (state) {
48+
if (args.samples) xfree(args.samples);
49+
if (args.data) xfree(args.data);
50+
return false;
51+
}
52+
53+
FILE *file = fopen(args.audio_path_str, "rb");
54+
if (file == NULL) {
55+
xfree(args.samples);
56+
xfree(args.data);
57+
return false;
58+
}
2159

2260
fseek(file, 78, SEEK_SET);
23-
fread(samples, sizeof(short), n_samples, file);
61+
fread(args.samples, sizeof(short), n_samples, file);
2462
fclose(file);
2563
for (int i = 0; i < n_samples; i++) {
26-
data[i] = samples[i]/32768.0;
64+
args.data[i] = args.samples[i] / 32768.0;
2765
}
66+
xfree(args.samples);
2867

2968
view->obj = obj;
30-
view->data = (void *)data;
69+
view->data = (void *)args.data;
3170
view->byte_size = sizeof(float) * n_samples;
3271
view->readonly = true;
3372
view->format = "f";
@@ -45,6 +84,10 @@ jfk_reader_get_memory_view(const VALUE obj, rb_memory_view_t *view, int flags)
4584
static bool
4685
jfk_reader_release_memory_view(const VALUE obj, rb_memory_view_t *view)
4786
{
87+
if (view->data) {
88+
xfree(view->data);
89+
view->data = NULL;
90+
}
4891
return true;
4992
}
5093

0 commit comments

Comments
 (0)