mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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>
This commit is contained in:
+2
-1
@@ -1571,7 +1571,8 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib);
|
||||
MRB_API void mrb_stack_extend(mrb_state*, mrb_int);
|
||||
|
||||
/* temporary memory allocation, only effective while GC arena is kept */
|
||||
MRB_API void* mrb_alloca(mrb_state *mrb, size_t);
|
||||
MRB_API void* mrb_temp_alloc(mrb_state *mrb, size_t);
|
||||
#define mrb_alloca(mrb, size) mrb_temp_alloc(mrb, size) /* for compatibility */
|
||||
|
||||
MRB_API void mrb_state_atexit(mrb_state *mrb, mrb_atexit_func func);
|
||||
|
||||
|
||||
@@ -885,32 +885,30 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass)
|
||||
* File.symlink("testfile", "link-to-test") #=> 0
|
||||
* File.readlink("link-to-test") #=> "testfile"
|
||||
*/
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
static mrb_value
|
||||
mrb_file_s_readlink(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
const char *path;
|
||||
size_t bufsize = 100;
|
||||
|
||||
mrb_get_args(mrb, "z", &path);
|
||||
|
||||
char *tmp = mrb_locale_from_utf8(path, -1);
|
||||
char *buf = (char*)mrb_malloc(mrb, bufsize);
|
||||
/* Use mrb_temp_alloc for exception safety - GC will clean up on exception */
|
||||
char *buf = (char*)mrb_temp_alloc(mrb, PATH_MAX);
|
||||
|
||||
int64_t rc;
|
||||
while ((rc = mrb_hal_io_readlink(mrb, tmp, buf, bufsize)) == (int64_t)bufsize) {
|
||||
bufsize += 100;
|
||||
buf = (char*)mrb_realloc(mrb, buf, bufsize);
|
||||
}
|
||||
int64_t rc = mrb_hal_io_readlink(mrb, tmp, buf, PATH_MAX);
|
||||
mrb_locale_free(tmp);
|
||||
if (rc == -1) {
|
||||
mrb_free(mrb, buf);
|
||||
mrb_sys_fail(mrb, path);
|
||||
}
|
||||
tmp = mrb_utf8_from_locale(buf, -1);
|
||||
|
||||
mrb_value ret = mrb_str_new(mrb, tmp, rc);
|
||||
mrb_utf8_free(tmp);
|
||||
mrb_free(mrb, buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#define INITIAL_BUFFER_SIZE 64
|
||||
#define MAX_BUFFER_SIZE 4096
|
||||
|
||||
/*
|
||||
@@ -60,12 +59,12 @@ mrb_time_strftime(mrb_state *mrb, mrb_value self)
|
||||
/* Process this segment (up to NUL or end of string) */
|
||||
if (segment_len > 0) {
|
||||
char *segment;
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
size_t n;
|
||||
|
||||
/* Create null-terminated copy of this segment */
|
||||
segment = (char *)mrb_malloc(mrb, (size_t)segment_len + 1);
|
||||
/* Use mrb_temp_alloc for exception safety - GC will clean up on exception */
|
||||
segment = (char *)mrb_temp_alloc(mrb, (size_t)segment_len + 1);
|
||||
memcpy(segment, fmt_ptr, (size_t)segment_len);
|
||||
segment[segment_len] = '\0';
|
||||
|
||||
@@ -74,7 +73,6 @@ mrb_time_strftime(mrb_state *mrb, mrb_value self)
|
||||
/* Scan for %- patterns in the format string */
|
||||
for (const char *p = segment; *p != '\0'; p++) {
|
||||
if (p[0] == '%' && p[1] == '-') {
|
||||
mrb_free(mrb, segment);
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR,
|
||||
"strftime format flag '%-' not supported on this platform (use '%%#' on Windows)");
|
||||
}
|
||||
@@ -82,33 +80,14 @@ mrb_time_strftime(mrb_state *mrb, mrb_value self)
|
||||
#endif
|
||||
|
||||
/* Allocate buffer for formatted output */
|
||||
buf_size = INITIAL_BUFFER_SIZE;
|
||||
buf = (char *)mrb_malloc(mrb, buf_size);
|
||||
/* Use mrb_temp_alloc with max size for exception safety */
|
||||
buf = (char *)mrb_temp_alloc(mrb, MAX_BUFFER_SIZE);
|
||||
|
||||
/* Try formatting; grow buffer if needed */
|
||||
while (1) {
|
||||
n = strftime(buf, buf_size, segment, tm);
|
||||
|
||||
/*
|
||||
* strftime returns 0 if:
|
||||
* 1. Buffer is too small (retry with larger buffer)
|
||||
* 2. Format produces empty result (stop retrying)
|
||||
* We distinguish by checking buffer size limit.
|
||||
*/
|
||||
if (n > 0 || buf_size >= MAX_BUFFER_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Double buffer size and retry */
|
||||
buf_size *= 2;
|
||||
buf = (char *)mrb_realloc(mrb, buf, buf_size);
|
||||
}
|
||||
/* Try formatting with max buffer size */
|
||||
n = strftime(buf, MAX_BUFFER_SIZE, segment, tm);
|
||||
|
||||
/* Append formatted output to result */
|
||||
mrb_str_cat(mrb, result, buf, n);
|
||||
|
||||
mrb_free(mrb, buf);
|
||||
mrb_free(mrb, segment);
|
||||
}
|
||||
|
||||
/* If there was a NUL, append it to result and advance past it */
|
||||
|
||||
Reference in New Issue
Block a user