Skip to content

Commit a5c3ee3

Browse files
byrootkddnewton
authored andcommitted
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.
1 parent cbe9692 commit a5c3ee3

17 files changed

Lines changed: 207 additions & 69 deletions

‎Doxyfile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ OUTPUT_DIRECTORY = doc
2424
JAVADOC_AUTOBRIEF = YES
2525
OPTIMIZE_OUTPUT_FOR_C = YES
2626
INPUT = src src/util include include/prism include/prism/util
27+
EXCLUDE = include/prism/debug_allocator.h
2728
HTML_OUTPUT = c
2829
SORT_MEMBER_DOCS = NO
2930
GENERATE_LATEX = NO

‎ext/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
#ifdefPRISM_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
VALUEvalue=parse_input(&input, &options);
930930

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

935935
pm_string_free(&input);

‎include/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+
#ifndefPRISM_DEBUG_ALLOCATOR_H
7+
#definePRISM_DEBUG_ALLOCATOR_H
8+
9+
#include<string.h>
10+
#include<stdio.h>
11+
#include<stdlib.h>
12+
13+
staticinlinevoid*
14+
pm_debug_malloc(size_tsize)
15+
{
16+
size_t*memory=xmalloc(size+sizeof(size_t));
17+
memory[0] =size;
18+
returnmemory+1;
19+
}
20+
21+
staticinlinevoid*
22+
pm_debug_calloc(size_tnmemb, size_tsize)
23+
{
24+
size_ttotal_size=nmemb*size;
25+
void*ptr=pm_debug_malloc(total_size);
26+
memset(ptr, 0, total_size);
27+
returnptr;
28+
}
29+
30+
staticinlinevoid*
31+
pm_debug_realloc(void*ptr, size_tsize)
32+
{
33+
if (ptr==NULL) {
34+
returnpm_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+
returnmemory+1;
42+
}
43+
44+
staticinlinevoid
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+
staticinlinevoid
54+
pm_debug_free_sized(void*ptr, size_told_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+
staticinlinevoid*
67+
pm_debug_realloc_sized(void*ptr, size_tsize, size_told_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+
returnpm_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+
returnpm_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+
#definexmalloc pm_debug_malloc
93+
#definexrealloc pm_debug_realloc
94+
#definexcalloc pm_debug_calloc
95+
#definexfree pm_debug_free
96+
#definexrealloc_sized pm_debug_realloc_sized
97+
#definexfree_sized pm_debug_free_sized
98+
99+
#endif

‎include/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+
#ifndefxfree_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+
#definexfree_sized(p, s) xfree(((void)(s), (p)))
216+
#endif
217+
218+
#ifndefxrealloc_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+
#definexrealloc_sized(p, ns, os) xrealloc((p), ((void)(os), (ns)))
225+
#endif
226+
227+
#ifdefPRISM_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.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",

‎src/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)