Skip to content

Commit 7fe5c2e

Browse files
matzclaude
andcommitted
gc.c: rename mrb_alloca() to mrb_temp_alloc() and fix memory leaks
rename mrb_alloca() to mrb_temp_alloc() for clearer naming - the new name better describes its purpose as GC-managed temporary allocation. keep mrb_alloca() as a macro alias for backward compatibility. apply mrb_temp_alloc() to fix potential memory leaks in: - mruby-strftime: if mrb_str_cat() raises, allocated buffers now cleaned by GC - mruby-io File.readlink: if mrb_str_new() raises, buffer now cleaned by GC Co-authored-by: Claude <noreply@anthropic.com>
1 parent c9e3af6 commit 7fe5c2e

File tree

4 files changed

+16
-38
lines changed

4 files changed

+16
-38
lines changed

include/mruby.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1571,7 +1571,8 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib);
15711571
MRB_API void mrb_stack_extend(mrb_state*, mrb_int);
15721572

15731573
/* temporary memory allocation, only effective while GC arena is kept */
1574-
MRB_API void* mrb_alloca(mrb_state *mrb, size_t);
1574+
MRB_API void* mrb_temp_alloc(mrb_state *mrb, size_t);
1575+
#define mrb_alloca(mrb, size) mrb_temp_alloc(mrb, size) /* for compatibility */
15751576

15761577
MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func);
15771578

mrbgems/mruby-io/src/file.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -885,32 +885,30 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass)
885885
* File.symlink("testfile", "link-to-test") #=> 0
886886
* File.readlink("link-to-test") #=> "testfile"
887887
*/
888+
#ifndef PATH_MAX
889+
#define PATH_MAX 4096
890+
#endif
891+
888892
static mrb_value
889893
mrb_file_s_readlink(mrb_state *mrb, mrb_value klass)
890894
{
891895
const char *path;
892-
size_t bufsize = 100;
893896

894897
mrb_get_args(mrb, "z", &path);
895898

896899
char *tmp = mrb_locale_from_utf8(path, -1);
897-
char *buf = (char*)mrb_malloc(mrb, bufsize);
900+
/* Use mrb_temp_alloc for exception safety - GC will clean up on exception */
901+
char *buf = (char*)mrb_temp_alloc(mrb, PATH_MAX);
898902

899-
int64_t rc;
900-
while ((rc = mrb_hal_io_readlink(mrb, tmp, buf, bufsize)) == (int64_t)bufsize) {
901-
bufsize += 100;
902-
buf = (char*)mrb_realloc(mrb, buf, bufsize);
903-
}
903+
int64_t rc = mrb_hal_io_readlink(mrb, tmp, buf, PATH_MAX);
904904
mrb_locale_free(tmp);
905905
if (rc == -1) {
906-
mrb_free(mrb, buf);
907906
mrb_sys_fail(mrb, path);
908907
}
909908
tmp = mrb_utf8_from_locale(buf, -1);
910909

911910
mrb_value ret = mrb_str_new(mrb, tmp, rc);
912911
mrb_utf8_free(tmp);
913-
mrb_free(mrb, buf);
914912

915913
return ret;
916914
}

mrbgems/mruby-strftime/src/strftime.c

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include <time.h>
1313
#include <string.h>
1414

15-
#define INITIAL_BUFFER_SIZE 64
1615
#define MAX_BUFFER_SIZE 4096
1716

1817
/*
@@ -60,12 +59,12 @@ mrb_time_strftime(mrb_state *mrb, mrb_value self)
6059
/* Process this segment (up to NUL or end of string) */
6160
if (segment_len > 0) {
6261
char *segment;
63-
size_t buf_size;
6462
char *buf;
6563
size_t n;
6664

6765
/* Create null-terminated copy of this segment */
68-
segment = (char *)mrb_malloc(mrb, (size_t)segment_len + 1);
66+
/* Use mrb_temp_alloc for exception safety - GC will clean up on exception */
67+
segment = (char *)mrb_temp_alloc(mrb, (size_t)segment_len + 1);
6968
memcpy(segment, fmt_ptr, (size_t)segment_len);
7069
segment[segment_len] = '\0';
7170

@@ -74,41 +73,21 @@ mrb_time_strftime(mrb_state *mrb, mrb_value self)
7473
/* Scan for %- patterns in the format string */
7574
for (const char *p = segment; *p != '\0'; p++) {
7675
if (p[0] == '%' && p[1] == '-') {
77-
mrb_free(mrb, segment);
7876
mrb_raisef(mrb, E_ARGUMENT_ERROR,
7977
"strftime format flag '%-' not supported on this platform (use '%%#' on Windows)");
8078
}
8179
}
8280
#endif
8381

8482
/* Allocate buffer for formatted output */
85-
buf_size = INITIAL_BUFFER_SIZE;
86-
buf = (char *)mrb_malloc(mrb, buf_size);
87-
88-
/* Try formatting; grow buffer if needed */
89-
while (1) {
90-
n = strftime(buf, buf_size, segment, tm);
91-
92-
/*
93-
* strftime returns 0 if:
94-
* 1. Buffer is too small (retry with larger buffer)
95-
* 2. Format produces empty result (stop retrying)
96-
* We distinguish by checking buffer size limit.
97-
*/
98-
if (n > 0 || buf_size >= MAX_BUFFER_SIZE) {
99-
break;
100-
}
83+
/* Use mrb_temp_alloc with max size for exception safety */
84+
buf = (char *)mrb_temp_alloc(mrb, MAX_BUFFER_SIZE);
10185

102-
/* Double buffer size and retry */
103-
buf_size *= 2;
104-
buf = (char *)mrb_realloc(mrb, buf, buf_size);
105-
}
86+
/* Try formatting with max buffer size */
87+
n = strftime(buf, MAX_BUFFER_SIZE, segment, tm);
10688

10789
/* Append formatted output to result */
10890
mrb_str_cat(mrb, result, buf, n);
109-
110-
mrb_free(mrb, buf);
111-
mrb_free(mrb, segment);
11291
}
11392

11493
/* If there was a NUL, append it to result and advance past it */

src/gc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ mrb_free(mrb_state *mrb, void *p)
266266
}
267267

268268
MRB_API void*
269-
mrb_alloca(mrb_state *mrb, size_t size)
269+
mrb_temp_alloc(mrb_state *mrb, size_t size)
270270
{
271271
struct RString *s;
272272
s = MRB_OBJ_ALLOC(mrb, MRB_TT_STRING, NULL);

0 commit comments

Comments
 (0)