Skip to content

Commit 3aa8927

Browse files
byrootmatzbot
authored andcommitted
[ruby/prism] Introduce xfree_sized and xrealloc_sized
This will allow prism to pass buffer sizes to the Ruby GC. It also helps avoid buffer overflow as it confirms the size was correctly tracked all the way until the buffer is freed. ruby/prism@a5c3ee3e4c
1 parent ebd5785 commit 3aa8927

File tree

16 files changed

+206
-69
lines changed

16 files changed

+206
-69
lines changed

lib/prism/prism.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Gem::Specification.new do |spec|
4848
"ext/prism/extension.h",
4949
"include/prism.h",
5050
"include/prism/ast.h",
51+
"include/prism/debug_allocator.h",
5152
"include/prism/defines.h",
5253
"include/prism/diagnostic.h",
5354
"include/prism/encoding.h",

prism/debug_allocator.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @file debug_allocator.h
3+
*
4+
* Decorate allocation function to ensure sizes are correct.
5+
*/
6+
#ifndef PRISM_DEBUG_ALLOCATOR_H
7+
#define PRISM_DEBUG_ALLOCATOR_H
8+
9+
#include <string.h>
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
13+
static inline void *
14+
pm_debug_malloc(size_t size)
15+
{
16+
size_t *memory = xmalloc(size + sizeof(size_t));
17+
memory[0] = size;
18+
return memory + 1;
19+
}
20+
21+
static inline void *
22+
pm_debug_calloc(size_t nmemb, size_t size)
23+
{
24+
size_t total_size = nmemb * size;
25+
void *ptr = pm_debug_malloc(total_size);
26+
memset(ptr, 0, total_size);
27+
return ptr;
28+
}
29+
30+
static inline void *
31+
pm_debug_realloc(void *ptr, size_t size)
32+
{
33+
if (ptr == NULL) {
34+
return pm_debug_malloc(size);
35+
}
36+
37+
size_t *memory = (size_t *)ptr;
38+
void *raw_memory = memory - 1;
39+
memory = (size_t *)xrealloc(raw_memory, size + sizeof(size_t));
40+
memory[0] = size;
41+
return memory + 1;
42+
}
43+
44+
static inline void
45+
pm_debug_free(void *ptr)
46+
{
47+
if (ptr != NULL) {
48+
size_t *memory = (size_t *)ptr;
49+
xfree(memory - 1);
50+
}
51+
}
52+
53+
static inline void
54+
pm_debug_free_sized(void *ptr, size_t old_size)
55+
{
56+
if (ptr != NULL) {
57+
size_t *memory = (size_t *)ptr;
58+
if (old_size != memory[-1]) {
59+
fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but freed with size %lu\n", ptr, memory[-1], old_size);
60+
abort();
61+
}
62+
xfree_sized(memory - 1, old_size + sizeof(size_t));
63+
}
64+
}
65+
66+
static inline void *
67+
pm_debug_realloc_sized(void *ptr, size_t size, size_t old_size)
68+
{
69+
if (ptr == NULL) {
70+
if (old_size != 0) {
71+
fprintf(stderr, "[BUG] realloc_sized called with NULL pointer and old size %lu\n", old_size);
72+
abort();
73+
}
74+
return pm_debug_malloc(size);
75+
}
76+
77+
size_t *memory = (size_t *)ptr;
78+
if (old_size != memory[-1]) {
79+
fprintf(stderr, "[BUG] buffer %p was allocated with size %lu but realloced with size %lu\n", ptr, memory[-1], old_size);
80+
abort();
81+
}
82+
return pm_debug_realloc(ptr, size);
83+
}
84+
85+
#undef xmalloc
86+
#undef xrealloc
87+
#undef xcalloc
88+
#undef xfree
89+
#undef xrealloc_sized
90+
#undef xfree_sized
91+
92+
#define xmalloc pm_debug_malloc
93+
#define xrealloc pm_debug_realloc
94+
#define xcalloc pm_debug_calloc
95+
#define xfree pm_debug_free
96+
#define xrealloc_sized pm_debug_realloc_sized
97+
#define xfree_sized pm_debug_free_sized
98+
99+
#endif

prism/defines.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,12 @@
161161
* ```
162162
* #ifndef PRISM_XALLOCATOR_H
163163
* #define PRISM_XALLOCATOR_H
164-
* #define xmalloc my_malloc
165-
* #define xrealloc my_realloc
166-
* #define xcalloc my_calloc
167-
* #define xfree my_free
164+
* #define xmalloc my_malloc
165+
* #define xrealloc my_realloc
166+
* #define xcalloc my_calloc
167+
* #define xfree my_free
168+
* #define xrealloc_sized my_realloc_sized // (optional)
169+
* #define xfree_sized my_free_sized // (optional)
168170
* #endif
169171
* ```
170172
*/
@@ -204,6 +206,28 @@
204206
#endif
205207
#endif
206208

209+
#ifndef xfree_sized
210+
/**
211+
* The free_sized function that should be used. This can be overridden with the
212+
* PRISM_XALLOCATOR define.
213+
* If not defined, defaults to calling xfree.
214+
*/
215+
#define xfree_sized(p, s) xfree(((void)(s), (p)))
216+
#endif
217+
218+
#ifndef xrealloc_sized
219+
/**
220+
* The xrealloc_sized function that should be used. This can be overridden with the
221+
* PRISM_XALLOCATOR define.
222+
* If not defined, defaults to calling xrealloc.
223+
*/
224+
#define xrealloc_sized(p, ns, os) xrealloc((p), ((void)(os), (ns)))
225+
#endif
226+
227+
#ifdef PRISM_BUILD_DEBUG
228+
#include "prism/debug_allocator.h"
229+
#endif
230+
207231
/**
208232
* If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible
209233
* switch that will turn off certain features of prism.

prism/extension.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ dump(int argc, VALUE *argv, VALUE self) {
413413
if (options.freeze) rb_obj_freeze(value);
414414

415415
#ifdef PRISM_BUILD_DEBUG
416-
xfree(dup);
416+
xfree_sized(dup, length);
417417
#endif
418418

419419
pm_string_free(&input);
@@ -929,7 +929,7 @@ parse(int argc, VALUE *argv, VALUE self) {
929929
VALUE value = parse_input(&input, &options);
930930

931931
#ifdef PRISM_BUILD_DEBUG
932-
xfree(dup);
932+
xfree_sized(dup, length);
933933
#endif
934934

935935
pm_string_free(&input);

prism/options.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@ pm_options_free(pm_options_t *options) {
226226
pm_string_free(&scope->locals[local_index]);
227227
}
228228

229-
xfree(scope->locals);
229+
xfree_sized(scope->locals, scope->locals_count * sizeof(pm_string_t));
230230
}
231231

232-
xfree(options->scopes);
232+
xfree_sized(options->scopes, options->scopes_count * sizeof(pm_options_scope_t));
233233
}
234234

235235
/**

0 commit comments

Comments
 (0)