From 62da4806322091aa2586f9ec376bd0a70600a32a Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sun, 1 Feb 2026 12:03:41 +0100 Subject: [PATCH 1/8] vm_eval.c,vm_trace.c: Use ruby_sized_xfree --- vm_eval.c | 2 +- vm_trace.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vm_eval.c b/vm_eval.c index cf01b4a62b37da..d968ee96b819bf 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1901,7 +1901,7 @@ pm_eval_make_iseq(VALUE src, VALUE fname, int line, pm_scope_node_t *next = prev->previous; pm_constant_id_list_free(&prev->locals); pm_scope_node_destroy(prev); - ruby_xfree(prev); + SIZED_FREE(prev); prev = next; } diff --git a/vm_trace.c b/vm_trace.c index 273faa5f888a4c..36409958344491 100644 --- a/vm_trace.c +++ b/vm_trace.c @@ -340,7 +340,7 @@ clean_hooks(rb_hook_list_t *list) change_c_events--; } } - xfree(hook); + SIZED_FREE(hook); } else { list->events |= hook->events; /* update active events */ @@ -350,7 +350,7 @@ clean_hooks(rb_hook_list_t *list) if (hook_list_targeted_p(list)) { if (list->events == 0) { - ruby_xfree(list); + SIZED_FREE(list); } } else { From 0a6e365fa036536a6fde88c430e50057264aad88 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sun, 1 Feb 2026 12:33:28 +0100 Subject: [PATCH 2/8] eval_jump.c: Use ruby_sized_xfree --- eval_jump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eval_jump.c b/eval_jump.c index 7593a35e360152..6ee8ff4a6f5f9a 100644 --- a/eval_jump.c +++ b/eval_jump.c @@ -101,7 +101,7 @@ exec_end_procs_chain(struct end_proc_data *volatile *procs, VALUE *errp) while ((link = *procs) != 0) { *procs = link->next; endproc = *link; - xfree(link); + SIZED_FREE(link); (*endproc.func) (endproc.data); *errp = errinfo; } From 1f58302e9f4810c0eb60c90b7933a30b5a0d05ff Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sun, 1 Feb 2026 12:39:24 +0100 Subject: [PATCH 3/8] internal/gc.h: Remove inlined allocation decorator functions --- internal/gc.h | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/internal/gc.h b/internal/gc.h index 5fa07a13fed125..d0bbc033882d17 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -198,9 +198,6 @@ RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add(size_t, size_t, size_t); void *rb_xrealloc_mul_add(const void *, size_t, size_t, size_t); RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add_mul(size_t, size_t, size_t, size_t); RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t); -static inline void *ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2)); -static inline void *ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3)); -static inline void ruby_sized_xfree_inlined(void *ptr, size_t size); void rb_gc_obj_id_moved(VALUE obj); void rb_gc_register_pinning_obj(VALUE obj); @@ -290,24 +287,6 @@ void rb_gc_writebarrier_remember(VALUE obj); const char *rb_obj_info(VALUE obj); void ruby_annotate_mmap(const void *addr, unsigned long size, const char *name); -static inline void * -ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) -{ - return ruby_sized_xrealloc(ptr, new_size, old_size); -} - -static inline void * -ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) -{ - return ruby_sized_xrealloc2(ptr, new_count, elemsiz, old_count); -} - -static inline void -ruby_sized_xfree_inlined(void *ptr, size_t size) -{ - ruby_sized_xfree(ptr, size); -} - # define SIZED_REALLOC_N(v, T, m, n) \ ((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n))) @@ -320,10 +299,6 @@ ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t ol return ruby_sized_xrealloc2(ptr, new_count, element_size, old_count); } -#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined -#define ruby_sized_xrealloc2 ruby_sized_xrealloc2_inlined -#define ruby_sized_xfree ruby_sized_xfree_inlined - void rb_gc_verify_shareable(VALUE); bool rb_gc_checking_shareable(void); From 32f2596984c30a767b5a0b0d2d890a5653e17960 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sun, 1 Feb 2026 12:17:51 +0100 Subject: [PATCH 4/8] thread_pthread.c: Use ruby_sized_xfree --- thread_none.c | 2 +- thread_pthread.c | 17 +++++++++-------- thread_pthread.h | 1 + thread_pthread_mn.c | 1 + thread_win32.c | 2 +- vm.c | 2 +- vm_core.h | 2 +- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/thread_none.c b/thread_none.c index e6616c05856ff9..1f7492fda878b7 100644 --- a/thread_none.c +++ b/thread_none.c @@ -336,7 +336,7 @@ rb_thread_prevent_fork(void *(*func)(void *), void *data) } void -rb_thread_malloc_stack_set(rb_thread_t *th, void *stack) +rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size) { // no-op } diff --git a/thread_pthread.c b/thread_pthread.c index 542690eca02f92..5b461efec877d6 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1822,8 +1822,8 @@ native_thread_destroy_atfork(struct rb_native_thread *nt) */ RB_ALTSTACK_FREE(nt->altstack); - ruby_xfree(nt->nt_context); - ruby_xfree(nt); + SIZED_FREE(nt->nt_context); + SIZED_FREE(nt); } } @@ -2201,7 +2201,7 @@ native_thread_create_dedicated(rb_thread_t *th) th->sched.malloc_stack = true; rb_ec_initialize_vm_stack(th->ec, vm_stack, vm_stack_word_size); th->sched.context_stack = vm_stack; - + th->sched.context_stack_size = vm_stack_word_size; int err = native_thread_create0(th->nt); if (!err) { @@ -2339,7 +2339,7 @@ rb_threadptr_sched_free(rb_thread_t *th) #if USE_MN_THREADS if (th->sched.malloc_stack) { // has dedicated - ruby_xfree(th->sched.context_stack); + SIZED_FREE_N((VALUE *)th->sched.context_stack, th->sched.context_stack_size); native_thread_destroy(th->nt); } else { @@ -2347,11 +2347,11 @@ rb_threadptr_sched_free(rb_thread_t *th) // TODO: how to free nt and nt->altstack? } - ruby_xfree(th->sched.context); + SIZED_FREE(th->sched.context); th->sched.context = NULL; // VM_ASSERT(th->sched.context == NULL); #else - ruby_xfree(th->sched.context_stack); + SIZED_FREE_N((VALUE *)th->sched.context_stack, th->sched.context_stack_size); native_thread_destroy(th->nt); #endif @@ -3447,7 +3447,7 @@ rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook) } if (success) { - ruby_xfree(hook); + SIZED_FREE(hook); } return success; } @@ -3489,10 +3489,11 @@ rb_thread_lock_native_thread(void) } void -rb_thread_malloc_stack_set(rb_thread_t *th, void *stack) +rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size) { th->sched.malloc_stack = true; th->sched.context_stack = stack; + th->sched.context_stack_size = stack_size; } #endif /* THREAD_SYSTEM_DEPENDENT_IMPLEMENTATION */ diff --git a/thread_pthread.h b/thread_pthread.h index 992e9fb0803d67..cd93182480d7b3 100644 --- a/thread_pthread.h +++ b/thread_pthread.h @@ -75,6 +75,7 @@ struct rb_thread_sched_item { bool finished; bool malloc_stack; void *context_stack; + size_t context_stack_size; struct coroutine_context *context; }; diff --git a/thread_pthread_mn.c b/thread_pthread_mn.c index 72a5d8fce2fe09..69e81e5fbcf00f 100644 --- a/thread_pthread_mn.c +++ b/thread_pthread_mn.c @@ -522,6 +522,7 @@ native_thread_create_shared(rb_thread_t *th) th->ec->machine.stack_start = (void *)((uintptr_t)machine_stack + machine_stack_size); th->ec->machine.stack_maxsize = machine_stack_size; // TODO th->sched.context_stack = machine_stack; + th->sched.context_stack_size = machine_stack_size; th->sched.context = ruby_xmalloc(sizeof(struct coroutine_context)); coroutine_initialize(th->sched.context, co_start, machine_stack, machine_stack_size); diff --git a/thread_win32.c b/thread_win32.c index 3fc763924846bd..5de79751f91c6e 100644 --- a/thread_win32.c +++ b/thread_win32.c @@ -1021,7 +1021,7 @@ rb_thread_prevent_fork(void *(*func)(void *), void *data) } void -rb_thread_malloc_stack_set(rb_thread_t *th, void *stack) +rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size) { // no-op } diff --git a/vm.c b/vm.c index 264bdfa1f23b2a..a9e952f705f131 100644 --- a/vm.c +++ b/vm.c @@ -3927,7 +3927,7 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm) size_t size = vm->default_params.thread_vm_stack_size / sizeof(VALUE); VALUE *stack = ALLOC_N(VALUE, size); rb_ec_initialize_vm_stack(th->ec, stack, size); - rb_thread_malloc_stack_set(th, stack); + rb_thread_malloc_stack_set(th, stack, size); } else { VM_ASSERT(th->ec->cfp == NULL); diff --git a/vm_core.h b/vm_core.h index 55ec08a6e238b7..b700a32909d6c7 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1999,7 +1999,7 @@ VALUE *rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t int rb_vm_get_sourceline(const rb_control_frame_t *); void rb_vm_stack_to_heap(rb_execution_context_t *ec); void ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame); -void rb_thread_malloc_stack_set(rb_thread_t *th, void *stack); +void rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size); rb_thread_t * ruby_thread_from_native(void); int ruby_thread_set_native(rb_thread_t *th); int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp); From 24bdf6a40e58b172ce67ff61d0b966f194d96757 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sun, 1 Feb 2026 12:54:55 +0100 Subject: [PATCH 5/8] transcode.c: Use ruby_sized_xfree --- depend | 20 +++++++++++++ transcode.c | 83 +++++++++++++++++++++++++++-------------------------- 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/depend b/depend index 2be15478970953..7525bcf396b901 100644 --- a/depend +++ b/depend @@ -17871,21 +17871,32 @@ time.$(OBJEXT): {$(VPATH)}timev.rbinc time.$(OBJEXT): {$(VPATH)}util.h time.$(OBJEXT): {$(VPATH)}vm_core.h time.$(OBJEXT): {$(VPATH)}vm_opts.h +transcode.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h +transcode.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h +transcode.$(OBJEXT): $(CCAN_DIR)/list/list.h +transcode.$(OBJEXT): $(CCAN_DIR)/str/str.h transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h transcode.$(OBJEXT): $(top_srcdir)/internal/array.h +transcode.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h +transcode.$(OBJEXT): $(top_srcdir)/internal/box.h transcode.$(OBJEXT): $(top_srcdir)/internal/class.h transcode.$(OBJEXT): $(top_srcdir)/internal/compilers.h transcode.$(OBJEXT): $(top_srcdir)/internal/encoding.h transcode.$(OBJEXT): $(top_srcdir)/internal/gc.h +transcode.$(OBJEXT): $(top_srcdir)/internal/imemo.h transcode.$(OBJEXT): $(top_srcdir)/internal/inits.h transcode.$(OBJEXT): $(top_srcdir)/internal/object.h +transcode.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h transcode.$(OBJEXT): $(top_srcdir)/internal/serial.h +transcode.$(OBJEXT): $(top_srcdir)/internal/set_table.h transcode.$(OBJEXT): $(top_srcdir)/internal/static_assert.h transcode.$(OBJEXT): $(top_srcdir)/internal/string.h transcode.$(OBJEXT): $(top_srcdir)/internal/transcode.h transcode.$(OBJEXT): $(top_srcdir)/internal/variable.h +transcode.$(OBJEXT): $(top_srcdir)/internal/vm.h transcode.$(OBJEXT): $(top_srcdir)/internal/warnings.h transcode.$(OBJEXT): {$(VPATH)}assert.h +transcode.$(OBJEXT): {$(VPATH)}atomic.h transcode.$(OBJEXT): {$(VPATH)}backward/2/assume.h transcode.$(OBJEXT): {$(VPATH)}backward/2/attributes.h transcode.$(OBJEXT): {$(VPATH)}backward/2/bool.h @@ -18055,15 +18066,24 @@ transcode.$(OBJEXT): {$(VPATH)}internal/value_type.h transcode.$(OBJEXT): {$(VPATH)}internal/variable.h transcode.$(OBJEXT): {$(VPATH)}internal/warning_push.h transcode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h +transcode.$(OBJEXT): {$(VPATH)}method.h transcode.$(OBJEXT): {$(VPATH)}missing.h +transcode.$(OBJEXT): {$(VPATH)}node.h transcode.$(OBJEXT): {$(VPATH)}onigmo.h transcode.$(OBJEXT): {$(VPATH)}oniguruma.h +transcode.$(OBJEXT): {$(VPATH)}ruby_assert.h +transcode.$(OBJEXT): {$(VPATH)}ruby_atomic.h +transcode.$(OBJEXT): {$(VPATH)}rubyparser.h transcode.$(OBJEXT): {$(VPATH)}shape.h transcode.$(OBJEXT): {$(VPATH)}st.h transcode.$(OBJEXT): {$(VPATH)}subst.h +transcode.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h +transcode.$(OBJEXT): {$(VPATH)}thread_native.h transcode.$(OBJEXT): {$(VPATH)}transcode.c transcode.$(OBJEXT): {$(VPATH)}transcode_data.h +transcode.$(OBJEXT): {$(VPATH)}vm_core.h transcode.$(OBJEXT): {$(VPATH)}vm_debug.h +transcode.$(OBJEXT): {$(VPATH)}vm_opts.h transcode.$(OBJEXT): {$(VPATH)}vm_sync.h util.$(OBJEXT): $(hdrdir)/ruby/ruby.h util.$(OBJEXT): $(top_srcdir)/internal/array.h diff --git a/transcode.c b/transcode.c index 86e828c47911a3..f8b0fec42ef275 100644 --- a/transcode.c +++ b/transcode.c @@ -16,6 +16,7 @@ #include "internal.h" #include "internal/array.h" #include "internal/inits.h" +#include "internal/gc.h" #include "internal/object.h" #include "internal/string.h" #include "internal/transcode.h" @@ -67,7 +68,7 @@ static unsigned char * allocate_converted_string(const char *sname, const char *dname, const unsigned char *str, size_t len, unsigned char *caller_dst_buf, size_t caller_dst_bufsize, - size_t *dst_len_ptr); + size_t *dst_len_ptr, size_t *dst_bufsize_ptr); /* dynamic structure, one per conversion (similar to iconv_t) */ /* may carry conversion state (e.g. for iso-2022-jp) */ @@ -138,6 +139,7 @@ struct rb_econv_t { const unsigned char *replacement_str; size_t replacement_len; + size_t replacement_bufsize; const char *replacement_enc; unsigned char *in_buf_start; @@ -186,7 +188,7 @@ static st_table *transcoder_table; static int free_inner_transcode_i(st_data_t key, st_data_t val, st_data_t arg) { - xfree((void *)val); + SIZED_FREE((transcoder_entry_t *)val); return ST_DELETE; } @@ -354,14 +356,14 @@ transcode_search_path(const char *sname, const char *dname, lookup_res = st_lookup(transcoder_table, (st_data_t)q->enc, &val); // src => table2 if (!lookup_res) { - xfree(q); + SIZED_FREE(q); continue; } table2 = (st_table *)val; if (st_lookup(table2, (st_data_t)dname, &val)) { // dest => econv st_add_direct(bfs.visited, (st_data_t)dname, (st_data_t)q->enc); - xfree(q); + SIZED_FREE(q); found = true; break; } @@ -370,14 +372,14 @@ transcode_search_path(const char *sname, const char *dname, st_foreach(table2, transcode_search_path_i, (st_data_t)&bfs); bfs.base_enc = NULL; - xfree(q); + SIZED_FREE(q); } } while (bfs.queue) { q = bfs.queue; bfs.queue = q->next; - xfree(q); + SIZED_FREE(q); } if (found) { @@ -873,12 +875,12 @@ rb_transcoding_close(rb_transcoding *tc) (tr->state_fini_func)(TRANSCODING_STATE(tc)); /* check return value? */ } if (TRANSCODING_STATE_EMBED_MAX < tr->state_size) - xfree(tc->state.ptr); + ruby_sized_xfree(tc->state.ptr, tr->state_size); if ((int)sizeof(tc->readbuf.ary) < tr->max_input) - xfree(tc->readbuf.ptr); + ruby_sized_xfree(tc->readbuf.ptr, tr->max_input); if ((int)sizeof(tc->writebuf.ary) < tr->max_output) - xfree(tc->writebuf.ptr); - xfree(tc); + ruby_sized_xfree(tc->writebuf.ptr, tr->max_output); + SIZED_FREE(tc); } static size_t @@ -914,6 +916,7 @@ rb_econv_alloc(int n_hint) ec->started = 0; ec->replacement_str = NULL; ec->replacement_len = 0; + ec->replacement_bufsize = 0; ec->replacement_enc = NULL; ec->replacement_allocated = 0; ec->in_buf_start = NULL; @@ -946,7 +949,7 @@ rb_econv_add_transcoder_at(rb_econv_t *ec, const rb_transcoder *tr, int i) if (ec->num_trans == ec->num_allocated) { n = ec->num_allocated * 2; - REALLOC_N(ec->elems, rb_econv_elem_t, n); + SIZED_REALLOC_N(ec->elems, rb_econv_elem_t, n, ec->num_allocated); ec->num_allocated = n; } @@ -1005,7 +1008,6 @@ rb_econv_open_by_transcoder_entries(int n, transcoder_entry_t **entries) struct trans_open_t { transcoder_entry_t **entries; - int num_additional; }; static void @@ -1014,7 +1016,7 @@ trans_open_i(const char *sname, const char *dname, int depth, void *arg) struct trans_open_t *toarg = arg; if (!toarg->entries) { - toarg->entries = ALLOC_N(transcoder_entry_t *, depth+1+toarg->num_additional); + toarg->entries = ALLOC_N(transcoder_entry_t *, depth + 1); } toarg->entries[depth] = get_transcoder_entry(sname, dname); } @@ -1036,19 +1038,17 @@ rb_econv_open0(const char *sname, const char *dname, int ecflags) sname = dname = ""; } else { - struct trans_open_t toarg; - toarg.entries = NULL; - toarg.num_additional = 0; + struct trans_open_t toarg = {0}; num_trans = transcode_search_path(sname, dname, trans_open_i, (void *)&toarg); entries = toarg.entries; if (num_trans < 0) { - xfree(entries); + SIZED_FREE_N(entries, num_trans); return NULL; } } ec = rb_econv_open_by_transcoder_entries(num_trans, entries); - xfree(entries); + SIZED_FREE_N(entries, num_trans); if (!ec) return NULL; @@ -1431,7 +1431,7 @@ output_hex_charref(rb_econv_t *ec) int ret; unsigned char utfbuf[1024]; const unsigned char *utf; - size_t utf_len; + size_t utf_len, utf_bufsize; int utf_allocated = 0; char charef_buf[16]; const unsigned char *p; @@ -1444,7 +1444,7 @@ output_hex_charref(rb_econv_t *ec) utf = allocate_converted_string(ec->last_error.source_encoding, "UTF-32BE", ec->last_error.error_bytes_start, ec->last_error.error_bytes_len, utfbuf, sizeof(utfbuf), - &utf_len); + &utf_len, &utf_bufsize); if (!utf) return -1; if (utf != utfbuf && utf != ec->last_error.error_bytes_start) @@ -1472,12 +1472,12 @@ output_hex_charref(rb_econv_t *ec) } if (utf_allocated) - xfree((void *)utf); + ruby_sized_xfree((void *)utf, utf_bufsize); return 0; fail: if (utf_allocated) - xfree((void *)utf); + ruby_sized_xfree((void *)utf, utf_bufsize); return -1; } @@ -1558,7 +1558,7 @@ static unsigned char * allocate_converted_string(const char *sname, const char *dname, const unsigned char *str, size_t len, unsigned char *caller_dst_buf, size_t caller_dst_bufsize, - size_t *dst_len_ptr) + size_t *dst_len_ptr, size_t *dst_bufsize_ptr) { unsigned char *dst_str; size_t dst_len; @@ -1601,7 +1601,7 @@ allocate_converted_string(const char *sname, const char *dname, dst_str = tmp; } else { - dst_str = xrealloc(dst_str, dst_bufsize); + dst_str = ruby_sized_xrealloc(dst_str, dst_bufsize, dst_bufsize / 2); } dp = dst_str+dst_len; res = rb_econv_convert(ec, &sp, str+len, &dp, dst_str+dst_bufsize, 0); @@ -1612,11 +1612,12 @@ allocate_converted_string(const char *sname, const char *dname, } rb_econv_close(ec); *dst_len_ptr = dst_len; + *dst_bufsize_ptr = dst_bufsize; return dst_str; fail: if (dst_str != caller_dst_buf) - xfree(dst_str); + ruby_sized_xfree(dst_str, dst_bufsize); rb_econv_close(ec); return NULL; } @@ -1629,7 +1630,7 @@ rb_econv_insert_output(rb_econv_t *ec, const char *insert_encoding = rb_econv_encoding_to_insert_output(ec); unsigned char insert_buf[4096]; const unsigned char *insert_str = NULL; - size_t insert_len; + size_t insert_len, insert_bufsize; int last_trans_index; rb_transcoding *tc; @@ -1652,7 +1653,7 @@ rb_econv_insert_output(rb_econv_t *ec, } else { insert_str = allocate_converted_string(str_encoding, insert_encoding, - str, len, insert_buf, sizeof(insert_buf), &insert_len); + str, len, insert_buf, sizeof(insert_buf), &insert_len, &insert_bufsize); if (insert_str == NULL) return -1; } @@ -1711,7 +1712,7 @@ rb_econv_insert_output(rb_econv_t *ec, size_t s = (*data_end_p - *buf_start_p) + need; if (s < need) goto fail; - buf = xrealloc(*buf_start_p, s); + buf = ruby_sized_xrealloc(*buf_start_p, s, buf_end_p - buf_start_p); *data_start_p = buf; *data_end_p = buf + (*data_end_p - *buf_start_p); *buf_start_p = buf; @@ -1728,12 +1729,12 @@ rb_econv_insert_output(rb_econv_t *ec, } if (insert_str != str && insert_str != insert_buf) - xfree((void*)insert_str); + ruby_sized_xfree((void *)insert_str, insert_bufsize); return 0; fail: if (insert_str != str && insert_str != insert_buf) - xfree((void*)insert_str); + ruby_sized_xfree((void *)insert_str, insert_bufsize); return -1; } @@ -1743,15 +1744,15 @@ rb_econv_close(rb_econv_t *ec) int i; if (ec->replacement_allocated) { - xfree((void *)ec->replacement_str); + SIZED_FREE_N((char *)ec->replacement_str, ec->replacement_len); } for (i = 0; i < ec->num_trans; i++) { rb_transcoding_close(ec->elems[i].tc); - xfree(ec->elems[i].out_buf_start); + ruby_sized_xfree(ec->elems[i].out_buf_start, ec->elems[i].out_buf_end - ec->elems[i].out_buf_start); } - xfree(ec->in_buf_start); - xfree(ec->elems); - xfree(ec); + SIZED_FREE_N(ec->in_buf_start, ec->in_buf_end - ec->in_buf_start); + SIZED_FREE_N(ec->elems, ec->num_allocated); + SIZED_FREE(ec); } size_t @@ -2046,7 +2047,7 @@ rb_econv_binmode(rb_econv_t *ec) for (i=0; i < num_trans; i++) { if (transcoder == ec->elems[i].tc->transcoder) { rb_transcoding_close(ec->elems[i].tc); - xfree(ec->elems[i].out_buf_start); + ruby_sized_xfree(ec->elems[i].out_buf_start, ec->elems[i].out_buf_end - ec->elems[i].out_buf_start); ec->num_trans--; } else @@ -2276,6 +2277,7 @@ make_replacement(rb_econv_t *ec) ec->replacement_str = replacement; ec->replacement_len = len; + ec->replacement_bufsize = len; ec->replacement_enc = repl_enc; ec->replacement_allocated = 0; return 0; @@ -2286,7 +2288,7 @@ rb_econv_set_replacement(rb_econv_t *ec, const unsigned char *str, size_t len, const char *encname) { unsigned char *str2; - size_t len2; + size_t len2, buf_size2; const char *encname2; encname2 = rb_econv_encoding_to_insert_output(ec); @@ -2294,21 +2296,22 @@ rb_econv_set_replacement(rb_econv_t *ec, if (!*encname2 || encoding_equal(encname, encname2)) { str2 = xmalloc(len); MEMCPY(str2, str, unsigned char, len); /* xxx: str may be invalid */ - len2 = len; + buf_size2 = len2 = len; encname2 = encname; } else { - str2 = allocate_converted_string(encname, encname2, str, len, NULL, 0, &len2); + str2 = allocate_converted_string(encname, encname2, str, len, NULL, 0, &len2, &buf_size2); if (!str2) return -1; } if (ec->replacement_allocated) { - xfree((void *)ec->replacement_str); + SIZED_FREE_N((char *)ec->replacement_str, ec->replacement_bufsize); } ec->replacement_allocated = 1; ec->replacement_str = str2; ec->replacement_len = len2; + ec->replacement_bufsize = buf_size2; ec->replacement_enc = encname2; return 0; } From 2ed817434f2958398773d8f3360a412fbf9384af Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sun, 1 Feb 2026 22:03:49 +0900 Subject: [PATCH 6/8] Win32: strip double quotes from the batch file name --- win32/configure.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/win32/configure.bat b/win32/configure.bat index d4e010ac4b0374..72c2a0139b6170 100755 --- a/win32/configure.bat +++ b/win32/configure.bat @@ -5,12 +5,12 @@ set PROMPT=$E[94m+$E[m$S if "%~dp0" == "%CD%\" ( echo don't run in win32 directory. exit /b 999 -) else if "%0" == "%~nx0" ( +) else if "%~0" == "%~nx0" ( set "WIN32DIR=%~$PATH:0" -) else if "%0" == "%~n0" ( +) else if "%~0" == "%~n0" ( set "WIN32DIR=%~$PATH:0" ) else ( - set "WIN32DIR=%0" + set "WIN32DIR=%~0" ) set "WIN32DIR=%WIN32DIR:\=/%:/:" From 911c1ca2823601d4bcf6e0e9b5a40f1d4aae51bd Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sun, 1 Feb 2026 22:08:27 +0900 Subject: [PATCH 7/8] Win32: keep --with-opt-dir as-is unless it is a real path Allow to expand environment variables in Makefile. E.g.: ```batch set VCPKG_INSTALLED=%HOME%\vcpkg\vcpkg_installed win32\configure.bat "--with-opt-dir=$(VCPKG_INSTALLED)/$(MACHINE)-windows" ``` --- win32/configure.bat | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/win32/configure.bat b/win32/configure.bat index 72c2a0139b6170..68ce7fb53f3cb4 100755 --- a/win32/configure.bat +++ b/win32/configure.bat @@ -5,12 +5,12 @@ set PROMPT=$E[94m+$E[m$S if "%~dp0" == "%CD%\" ( echo don't run in win32 directory. exit /b 999 -) else if "%~0" == "%~nx0" ( +) else if "%~0" == "%~nx0" ( set "WIN32DIR=%~$PATH:0" -) else if "%~0" == "%~n0" ( +) else if "%~0" == "%~n0" ( set "WIN32DIR=%~$PATH:0" ) else ( - set "WIN32DIR=%~0" + set "WIN32DIR=%~0" ) set "WIN32DIR=%WIN32DIR:\=/%:/:" @@ -204,9 +204,11 @@ goto :loop ; ) :optdir-loop for /f "delims=; tokens=1,*" %%I in ("%arg%") do (set "d=%%I" & set "arg=%%J") - pushd %d:/=\% && ( + pushd %d:/=\% 2> nul && ( set "optdirs=%optdirs%;%CD:\=/%" popd + ) || ( + set "optdirs=%optdirs%;%d:\=/%" ) if not "%arg%" == "" goto :optdir-loop goto :loop ; @@ -239,7 +241,7 @@ goto :EOF exit /b 1 :end if "%debug_configure%" == "yes" (type %confargs%) -if not "%optdirs%" == "" (echo>>%config_make% optdirs = %optdirs:~1%) +if defined optdirs (for %%I in ("%optdirs:~1%") do echo>>%config_make% optdirs = %%~I) ( echo. echo configure_args = \ From a93604b5ed813c43aca572ad64c1a7b66b715429 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sat, 31 Jan 2026 19:14:25 -0500 Subject: [PATCH 8/8] [DOC] Fix dead links in options.md --- doc/language/options.md | 80 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/doc/language/options.md b/doc/language/options.md index 3421d73f552b40..5f56ef0dd46db7 100644 --- a/doc/language/options.md +++ b/doc/language/options.md @@ -61,15 +61,15 @@ nil See also: -- {Option -a}[rdoc-ref:@a-3A+Split+Input+Lines+into+Fields]: +- {Option -a}[rdoc-ref:@-a+Split+Input+Lines+into+Fields]: Split input lines into fields. -- {Option -F}[rdoc-ref:@F-3A+Set+Input+Field+Separator]: +- {Option -F}[rdoc-ref:@-F+Set+Input+Field+Separator]: Set input field separator. -- {Option -l}[rdoc-ref:@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]: +- {Option -l}[rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines]: Set output record separator; chop lines. -- {Option -n}[rdoc-ref:@n-3A+Run+Program+in+gets+Loop]: +- {Option -n}[rdoc-ref:@-n+Run+Program+in+gets+Loop]: Run program in `gets` loop. -- {Option -p}[rdoc-ref:@p-3A+-n-2C+with+Printing]: +- {Option -p}[rdoc-ref:@-p+-n+with+Printing]: `-n`, with printing. ### `-a`: Split Input Lines into Fields @@ -91,15 +91,15 @@ and the default field separator is `$;`. See also: -- {Option -0}[rdoc-ref:@0-3A+Set+-24-2F+-28Input+Record+Separator-29]: +- {Option -0}[rdoc-ref:@-0+Set++Input+Record+Separator]: Set `$/` (input record separator). -- {Option -F}[rdoc-ref:@F-3A+Set+Input+Field+Separator]: +- {Option -F}[rdoc-ref:@-F+Set+Input+Field+Separator]: Set input field separator. -- {Option -l}[rdoc-ref:@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]: +- {Option -l}[rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines]: Set output record separator; chop lines. -- {Option -n}[rdoc-ref:@n-3A+Run+Program+in+gets+Loop]: +- {Option -n}[rdoc-ref:@-n+Run+Program+in+gets+Loop]: Run program in `gets` loop. -- {Option -p}[rdoc-ref:@p-3A+-n-2C+with+Printing]: +- {Option -p}[rdoc-ref:@-p+-n+with+Printing]: `-n`, with printing. ### `-c`: Check Syntax @@ -186,9 +186,9 @@ Whitespace between the option and its argument may be omitted. See also: -- {Option --external-encoding}[options_md.html#label--external-encoding-3A+Set+Default+External+Encoding]: +- {Option --external-encoding}[rdoc-ref:@--external+encoding+Set+Default+External+Encoding]: Set default external encoding. -- {Option --internal-encoding}[options_md.html#label--internal-encoding-3A+Set+Default+Internal+Encoding]: +- {Option --internal-encoding}[rdoc-ref:@--internal+encoding+Set+Default+Internal+Encoding]: Set default internal encoding. Option `--encoding` is an alias for option `-E`. @@ -221,15 +221,15 @@ The argument must immediately follow the option See also: -- {Option -0}[rdoc-ref:@0-3A+Set+-24-2F+-28Input+Record+Separator-29]: +- {Option -0}[rdoc-ref:@-0+Set++Input+Record+Separator]: Set `$/` (input record separator). -- {Option -a}[rdoc-ref:@a-3A+Split+Input+Lines+into+Fields]: +- {Option -a}[rdoc-ref:@-a+Split+Input+Lines+into+Fields]: Split input lines into fields. -- {Option -l}[rdoc-ref:@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]: +- {Option -l}[rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines]: Set output record separator; chop lines. -- {Option -n}[rdoc-ref:@n-3A+Run+Program+in+gets+Loop]: +- {Option -n}[rdoc-ref:@-n+Run+Program+in+gets+Loop]: Run program in `gets` loop. -- {Option -p}[rdoc-ref:@p-3A+-n-2C+with+Printing]: +- {Option -p}[rdoc-ref:@-p+-n+with+Printing]: `-n`, with printing. ### `-h`: Print Short Help Message @@ -307,15 +307,15 @@ $ ruby -ln -e 'p $_' desiderata.txt See also: -- {Option -0}[rdoc-ref:@0-3A+Set+-24-2F+-28Input+Record+Separator-29]: +- {Option -0}[rdoc-ref:@-0+Set++Input+Record+Separator]: Set `$/` (input record separator). -- {Option -a}[rdoc-ref:@a-3A+Split+Input+Lines+into+Fields]: +- {Option -a}[rdoc-ref:@-a+Split+Input+Lines+into+Fields]: Split input lines into fields. -- {Option -F}[rdoc-ref:@F-3A+Set+Input+Field+Separator]: +- {Option -F}[rdoc-ref:@-F+Set+Input+Field+Separator]: Set input field separator. -- {Option -n}[rdoc-ref:@n-3A+Run+Program+in+gets+Loop]: +- {Option -n}[rdoc-ref:@-n+Run+Program+in+gets+Loop]: Run program in `gets` loop. -- {Option -p}[rdoc-ref:@p-3A+-n-2C+with+Printing]: +- {Option -p}[rdoc-ref:@-p+-n+with+Printing]: `-n`, with printing. ### `-n`: Run Program in `gets` Loop @@ -341,15 +341,15 @@ be on good terms with all persons. See also: -- {Option -0}[rdoc-ref:@0-3A+Set+-24-2F+-28Input+Record+Separator-29]: +- {Option -0}[rdoc-ref:@-0+Set++Input+Record+Separator]: Set `$/` (input record separator). -- {Option -a}[rdoc-ref:@a-3A+Split+Input+Lines+into+Fields]: +- {Option -a}[rdoc-ref:@-a+Split+Input+Lines+into+Fields]: Split input lines into fields. -- {Option -F}[rdoc-ref:@F-3A+Set+Input+Field+Separator]: +- {Option -F}[rdoc-ref:@-F+Set+Input+Field+Separator]: Set input field separator. -- {Option -l}[rdoc-ref:@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]: +- {Option -l}[rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines]: Set output record separator; chop lines. -- {Option -p}[rdoc-ref:@p-3A+-n-2C+with+Printing]: +- {Option -p}[rdoc-ref:@-p+-n+with+Printing]: `-n`, with printing. ### `-p`: `-n`, with Printing @@ -370,15 +370,15 @@ be on good terms with all persons. See also: -- {Option -0}[rdoc-ref:@0-3A+Set+-24-2F+-28Input+Record+Separator-29]: +- {Option -0}[rdoc-ref:@-0+Set++Input+Record+Separator]: Set `$/` (input record separator). -- {Option -a}[rdoc-ref:@a-3A+Split+Input+Lines+into+Fields]: +- {Option -a}[rdoc-ref:@-a+Split+Input+Lines+into+Fields]: Split input lines into fields. -- {Option -F}[rdoc-ref:@F-3A+Set+Input+Field+Separator]: +- {Option -F}[rdoc-ref:@-F+Set+Input+Field+Separator]: Set input field separator. -- {Option -l}[rdoc-ref:@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]: +- {Option -l}[rdoc-ref:@-l+Set+Output+Record+Separator+Chop+Lines]: Set output record separator; chop lines. -- {Option -n}[rdoc-ref:@n-3A+Run+Program+in+gets+Loop]: +- {Option -n}[rdoc-ref:@-n+Run+Program+in+gets+Loop]: Run program in `gets` loop. ### `-r`: Require Library @@ -427,7 +427,7 @@ $ ruby -s t.rb -foo=baz -bar=bat ``` The option may not be used with -{option -e}[rdoc-ref:@e-3A+Execute+Given+Ruby+Code] +{option -e}[rdoc-ref:@-e+Execute+Given+Ruby+Code] ### `-S`: Search Directories in `ENV['PATH']` @@ -595,7 +595,7 @@ The supported features: - `frozen-string-literal`: Freeze all string literals (default: disabled). - `jit`: JIT compiler (default: disabled). -See also {option --enable}[options_md.html#label--enable-3A+Enable+Features]. +See also {option --enable}[rdoc-ref:@--enable+Enable+Features]. ### `--dump`: Dump Items @@ -606,15 +606,15 @@ Some of the argument values cause the command to behave as if a different option was given: - `--dump=copyright`: - Same as {option \-\-copyright}[options_md.html#label--copyright-3A+Print+Ruby+Copyright]. + Same as {option \-\-copyright}[rdoc-ref:@--copyright+Print+Ruby+Copyright]. - `--dump=help`: - Same as {option \-\-help}[options_md.html#label--help-3A+Print+Help+Message]. + Same as {option \-\-help}[rdoc-ref:@--help+Print+Help+Message]. - `--dump=syntax`: - Same as {option -c}[rdoc-ref:@c-3A+Check+Syntax]. + Same as {option -c}[rdoc-ref:@-c+Check+Syntax]. - `--dump=usage`: - Same as {option -h}[rdoc-ref:@h-3A+Print+Short+Help+Message]. + Same as {option -h}[rdoc-ref:@-h+Print+Short+Help+Message]. - `--dump=version`: - Same as {option \-\-version}[options_md.html#label--version-3A+Print+Ruby+Version]. + Same as {option \-\-version}[rdoc-ref:@--version+Print+Ruby+Version]. For other argument values and examples, see {Option --dump}[option_dump_md.html]. @@ -629,7 +629,7 @@ ruby --enable=gems,rubyopt t.rb ``` For the features, -see {option --disable}[options_md.html#label--disable-3A+Disable+Features]. +see {option --disable}[rdoc-ref:@--disable+Disable+Features]. ### `--encoding`: Alias for `-E`.