summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/gc.c b/gc.c
index be883583bb..807d8eb2ec 100644
--- a/gc.c
+++ b/gc.c
@@ -74,16 +74,22 @@ static void run_final();
static VALUE nomem_error;
static void garbage_collect();
+NORETURN(void rb_exc_jump _((VALUE)));
+
void
rb_memerror()
{
- static int recurse = 0;
+ rb_thread_t th = rb_curr_thread;
- if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) {
+ if (!nomem_error ||
+ (rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) {
fprintf(stderr, "[FATAL] failed to allocate memory\n");
exit(1);
}
- recurse++;
+ if (rb_thread_raised_p(th, RAISED_NOMEMORY)) {
+ rb_exc_jump(nomem_error);
+ }
+ rb_thread_raised_set(th, RAISED_NOMEMORY);
rb_exc_raise(nomem_error);
}
@@ -97,9 +103,8 @@ ruby_xmalloc(size)
rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
}
if (size == 0) size = 1;
- malloc_increase += size;
- if (malloc_increase > malloc_limit) {
+ if ((malloc_increase+size) > malloc_limit) {
garbage_collect();
}
RUBY_CRITICAL(mem = malloc(size));
@@ -110,6 +115,7 @@ ruby_xmalloc(size)
rb_memerror();
}
}
+ malloc_increase += size;
return mem;
}
@@ -138,7 +144,6 @@ ruby_xrealloc(ptr, size)
}
if (!ptr) return xmalloc(size);
if (size == 0) size = 1;
- malloc_increase += size;
RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) {
garbage_collect();
@@ -147,6 +152,7 @@ ruby_xrealloc(ptr, size)
rb_memerror();
}
}
+ malloc_increase += size;
return mem;
}
@@ -2064,6 +2070,8 @@ Init_GC()
rb_global_variable(&nomem_error);
nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory");
+ OBJ_TAINT(nomem_error);
+ OBJ_FREEZE(nomem_error);
rb_define_method(rb_mKernel, "hash", rb_obj_id, 0);
rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0);