summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2026-01-31 08:53:48 +0100
committerJean Boussier <jean.boussier@gmail.com>2026-01-31 10:35:48 +0100
commitbd6fa7f5cca426901bc9162724966339440bc6cb (patch)
tree57363875f68945549cb9bc47b7e63950b1d5c6b0
parentdb52e98520349e2bfcd471a0c2f96d696a4f7498 (diff)
ruby_xfree: reject memory allocated by ruby_mimalloc
-rw-r--r--cont.c9
-rw-r--r--gc/default/default.c4
-rw-r--r--ractor.c8
-rw-r--r--ractor_core.h1
-rw-r--r--vm.c8
-rw-r--r--vm_core.h1
-rw-r--r--vm_trace.c2
7 files changed, 29 insertions, 4 deletions
diff --git a/cont.c b/cont.c
index 8af093a316..4582466fac 100644
--- a/cont.c
+++ b/cont.c
@@ -215,6 +215,7 @@ typedef struct rb_context_struct {
enum context_type type;
int argc;
int kw_splat;
+ bool root;
VALUE self;
VALUE value;
@@ -1102,7 +1103,12 @@ cont_free(void *ptr)
VM_ASSERT(cont->jit_cont != NULL);
jit_cont_free(cont->jit_cont);
/* free rb_cont_t or rb_fiber_t */
- ruby_xfree(ptr);
+ if (cont->root) {
+ ruby_mimfree(ptr);
+ }
+ else {
+ ruby_xfree(ptr);
+ }
RUBY_FREE_LEAVE("cont");
}
@@ -2574,6 +2580,7 @@ rb_threadptr_root_fiber_setup(rb_thread_t *th)
}
fiber->cont.type = FIBER_CONTEXT;
+ fiber->cont.root = true;
fiber->cont.saved_ec.fiber_ptr = fiber;
fiber->cont.saved_ec.serial = next_ec_serial(th->ractor);
fiber->cont.saved_ec.thread_ptr = th;
diff --git a/gc/default/default.c b/gc/default/default.c
index 90232c7618..bfddb08ea5 100644
--- a/gc/default/default.c
+++ b/gc/default/default.c
@@ -8279,6 +8279,10 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
#if CALC_EXACT_MALLOC_SIZE
struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
#if VERIFY_FREE_SIZE
+ if (!info->size) {
+ rb_bug("buffer %p has no recorded size. Was it allocated with ruby_mimalloc? If so it should be freed with ruby_mimfree", ptr);
+ }
+
if (old_size && (old_size + sizeof(struct malloc_obj_info)) != info->size) {
rb_bug("buffer %p freed with old_size=%lu, but was allocated with size=%lu", ptr, old_size, info->size - sizeof(struct malloc_obj_info));
}
diff --git a/ractor.c b/ractor.c
index 2dcbbd10a0..da1db8d803 100644
--- a/ractor.c
+++ b/ractor.c
@@ -298,7 +298,12 @@ ractor_free(void *ptr)
}
ractor_sync_free(r);
- ruby_xfree(r);
+ if (r->main_ractor) {
+ ruby_mimfree(r);
+ }
+ else {
+ ruby_xfree(r);
+ }
}
static size_t
@@ -478,6 +483,7 @@ rb_ractor_main_alloc(void)
r->pub.self = Qnil;
r->newobj_cache = rb_gc_ractor_cache_alloc(r);
r->next_ec_serial = 1;
+ r->main_ractor = true;
ruby_single_main_ractor = r;
return r;
diff --git a/ractor_core.h b/ractor_core.h
index d112ff8724..d795136b70 100644
--- a/ractor_core.h
+++ b/ractor_core.h
@@ -104,6 +104,7 @@ struct rb_ractor_struct {
VALUE debug;
bool malloc_gc_disabled;
+ bool main_ractor;
void *newobj_cache;
}; // rb_ractor_t is defined in vm_core.h
diff --git a/vm.c b/vm.c
index 2cae6779d9..f2e2ba1b89 100644
--- a/vm.c
+++ b/vm.c
@@ -3821,7 +3821,12 @@ thread_free(void *ptr)
else {
// ruby_xfree(th->nt);
// TODO: MN system collect nt, but without MN system it should be freed here.
- ruby_xfree(th);
+ if (th->main_thread) {
+ ruby_mimfree(th);
+ }
+ else {
+ ruby_xfree(th);
+ }
}
RUBY_FREE_LEAVE("thread");
@@ -4594,6 +4599,7 @@ Init_BareVM(void)
vm->global_hooks.type = hook_list_type_global;
// setup main thread
+ th->main_thread = 1;
th->nt = ZALLOC(struct rb_native_thread);
th->vm = vm;
th->ractor = vm->ractor.main_ractor = rb_ractor_main_alloc();
diff --git a/vm_core.h b/vm_core.h
index 68adc5eac1..e1a21afc01 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -1152,6 +1152,7 @@ typedef struct rb_thread_struct {
BITFIELD(enum rb_thread_status, status, 2);
/* bit flags */
+ unsigned int main_thread : 1;
unsigned int has_dedicated_nt : 1;
unsigned int to_kill : 1;
unsigned int abort_on_exception: 1;
diff --git a/vm_trace.c b/vm_trace.c
index 0090541275..11cf7f55b5 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -1901,7 +1901,7 @@ void
rb_vm_postponed_job_free(void)
{
rb_vm_t *vm = GET_VM();
- ruby_xfree(vm->postponed_job_queue);
+ ruby_mimfree(vm->postponed_job_queue);
vm->postponed_job_queue = NULL;
}