summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2026-01-30 09:41:27 +0100
committerJean Boussier <jean.boussier@gmail.com>2026-01-30 14:48:37 +0100
commit3c100019a4a1b0ef66db76ec3b14f63eac51dd4d (patch)
treea04dfe22bf18c185d8a50a19018db740412815c3
parentdddb6511184e24413618645af9ed1ea7e8ae06ac (diff)
st.c: Use ruby_sized_xfree
Followup: https://github.com/ruby/ruby/pull/15989 This feeds the GC with useful allocation metrics, but also ensure we're correctly keeping track of our allocation sizes which is beneficial for safety. It also allows to use C23's `free_sized`.
-rw-r--r--depend34
-rw-r--r--st.c103
2 files changed, 106 insertions, 31 deletions
diff --git a/depend b/depend
index 7372902666..2be1547897 100644
--- a/depend
+++ b/depend
@@ -16298,16 +16298,28 @@ sprintf.$(OBJEXT): {$(VPATH)}st.h
sprintf.$(OBJEXT): {$(VPATH)}subst.h
sprintf.$(OBJEXT): {$(VPATH)}util.h
sprintf.$(OBJEXT): {$(VPATH)}vsnprintf.c
+st.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+st.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+st.$(OBJEXT): $(CCAN_DIR)/list/list.h
+st.$(OBJEXT): $(CCAN_DIR)/str/str.h
st.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+st.$(OBJEXT): $(top_srcdir)/internal/array.h
+st.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
st.$(OBJEXT): $(top_srcdir)/internal/bits.h
+st.$(OBJEXT): $(top_srcdir)/internal/box.h
st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+st.$(OBJEXT): $(top_srcdir)/internal/gc.h
st.$(OBJEXT): $(top_srcdir)/internal/hash.h
+st.$(OBJEXT): $(top_srcdir)/internal/imemo.h
st.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+st.$(OBJEXT): $(top_srcdir)/internal/serial.h
st.$(OBJEXT): $(top_srcdir)/internal/set_table.h
st.$(OBJEXT): $(top_srcdir)/internal/st.h
st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+st.$(OBJEXT): $(top_srcdir)/internal/vm.h
st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
st.$(OBJEXT): {$(VPATH)}assert.h
+st.$(OBJEXT): {$(VPATH)}atomic.h
st.$(OBJEXT): {$(VPATH)}backward/2/assume.h
st.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
st.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -16319,6 +16331,9 @@ st.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
st.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
st.$(OBJEXT): {$(VPATH)}config.h
st.$(OBJEXT): {$(VPATH)}defines.h
+st.$(OBJEXT): {$(VPATH)}encoding.h
+st.$(OBJEXT): {$(VPATH)}id.h
+st.$(OBJEXT): {$(VPATH)}id_table.h
st.$(OBJEXT): {$(VPATH)}intern.h
st.$(OBJEXT): {$(VPATH)}internal.h
st.$(OBJEXT): {$(VPATH)}internal/abi.h
@@ -16392,6 +16407,15 @@ st.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
st.$(OBJEXT): {$(VPATH)}internal/ctype.h
st.$(OBJEXT): {$(VPATH)}internal/dllexport.h
st.$(OBJEXT): {$(VPATH)}internal/dosish.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+st.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
st.$(OBJEXT): {$(VPATH)}internal/error.h
st.$(OBJEXT): {$(VPATH)}internal/eval.h
st.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -16463,11 +16487,21 @@ st.$(OBJEXT): {$(VPATH)}internal/value_type.h
st.$(OBJEXT): {$(VPATH)}internal/variable.h
st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+st.$(OBJEXT): {$(VPATH)}method.h
st.$(OBJEXT): {$(VPATH)}missing.h
+st.$(OBJEXT): {$(VPATH)}node.h
+st.$(OBJEXT): {$(VPATH)}onigmo.h
+st.$(OBJEXT): {$(VPATH)}oniguruma.h
st.$(OBJEXT): {$(VPATH)}ruby_assert.h
+st.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+st.$(OBJEXT): {$(VPATH)}rubyparser.h
st.$(OBJEXT): {$(VPATH)}st.c
st.$(OBJEXT): {$(VPATH)}st.h
st.$(OBJEXT): {$(VPATH)}subst.h
+st.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+st.$(OBJEXT): {$(VPATH)}thread_native.h
+st.$(OBJEXT): {$(VPATH)}vm_core.h
+st.$(OBJEXT): {$(VPATH)}vm_opts.h
strftime.$(OBJEXT): $(hdrdir)/ruby/ruby.h
strftime.$(OBJEXT): $(top_srcdir)/internal/compilers.h
strftime.$(OBJEXT): $(top_srcdir)/internal/encoding.h
diff --git a/st.c b/st.c
index 8937f7935f..7891947549 100644
--- a/st.c
+++ b/st.c
@@ -107,6 +107,7 @@
#elif defined RUBY_EXPORT
#include "internal.h"
#include "internal/bits.h"
+#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/sanitizers.h"
#include "internal/set_table.h"
@@ -173,7 +174,14 @@ static const struct st_hash_type type_strcasehash = {
#define malloc ruby_xmalloc
#define calloc ruby_xcalloc
#define realloc ruby_xrealloc
+#define sized_realloc ruby_sized_xrealloc
#define free ruby_xfree
+#define sized_free ruby_sized_xfree
+#define free_fixed_ptr(v) ruby_sized_xfree((v), sizeof(*(v)))
+#else
+#define sized_realloc(ptr, new_size, old_size) realloc(ptr, new_size)
+#define sized_free(v, s) free(v)
+#define free_fixed_ptr(v) free(v)
#endif
#define EQUAL(tab,x,y) ((x) == (y) || (*(tab)->type->compare)((x),(y)) == 0)
@@ -551,7 +559,7 @@ st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type,
tab->bins = (st_index_t *) malloc(bins_size(tab));
#ifndef RUBY
if (tab->bins == NULL) {
- free(tab);
+ free_fixed_ptr(tab);
return NULL;
}
#endif
@@ -585,7 +593,7 @@ st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
st_init_existing_table_with_size(tab, type, size);
#else
if (st_init_existing_table_with_size(tab, type, size) == NULL) {
- free(tab);
+ free_fixed_ptr(tab);
return NULL;
}
#endif
@@ -661,13 +669,36 @@ st_clear(st_table *tab)
tab->rebuilds_num++;
}
+static inline size_t
+st_entries_memsize(const st_table *tab)
+{
+ return get_allocated_entries(tab) * sizeof(st_table_entry);
+}
+
+static inline size_t
+st_bins_memsize(const st_table *tab)
+{
+ return tab->bins == NULL ? 0 : bins_size(tab);
+}
+
+static inline void
+st_free_entries(const st_table *tab)
+{
+ sized_free(tab->entries, st_entries_memsize(tab));
+}
+
+static inline void
+st_free_bins(const st_table *tab)
+{
+ sized_free(tab->bins, st_bins_memsize(tab));
+}
/* Free table TAB space. */
void
st_free_table(st_table *tab)
{
- free(tab->bins);
- free(tab->entries);
- free(tab);
+ st_free_bins(tab);
+ st_free_entries(tab);
+ free_fixed_ptr(tab);
}
/* Return byte size of memory allocated for table TAB. */
@@ -676,8 +707,8 @@ st_memsize(const st_table *tab)
{
RUBY_ASSERT(tab != NULL);
return(sizeof(st_table)
- + (tab->bins == NULL ? 0 : bins_size(tab))
- + get_allocated_entries(tab) * sizeof(st_table_entry));
+ + st_bins_memsize(tab)
+ + st_entries_memsize(tab));
}
static st_index_t
@@ -799,14 +830,15 @@ rebuild_table_with(st_table *const new_tab, st_table *const tab)
static void
rebuild_move_table(st_table *const new_tab, st_table *const tab)
{
+ st_free_bins(tab);
+ st_free_entries(tab);
+
tab->entry_power = new_tab->entry_power;
tab->bin_power = new_tab->bin_power;
tab->size_ind = new_tab->size_ind;
- free(tab->bins);
tab->bins = new_tab->bins;
- free(tab->entries);
tab->entries = new_tab->entries;
- free(new_tab);
+ free_fixed_ptr(new_tab);
}
static void
@@ -2135,16 +2167,17 @@ st_expand_table(st_table *tab, st_index_t siz)
tmp = st_init_table_with_size(tab->type, siz);
n = get_allocated_entries(tab);
MEMCPY(tmp->entries, tab->entries, st_table_entry, n);
- free(tab->entries);
- free(tab->bins);
- free(tmp->bins);
+ st_free_bins(tab);
+ st_free_entries(tab);
+ st_free_bins(tmp);
+
tab->entry_power = tmp->entry_power;
tab->bin_power = tmp->bin_power;
tab->size_ind = tmp->size_ind;
tab->entries = tmp->entries;
tab->bins = NULL;
tab->rebuilds_num++;
- free(tmp);
+ free_fixed_ptr(tmp);
}
/* Rehash using linear search. Return TRUE if we found that the table
@@ -2156,7 +2189,7 @@ st_rehash_linear(st_table *tab)
st_index_t i, j;
st_table_entry *p, *q;
- free(tab->bins);
+ st_free_bins(tab);
tab->bins = NULL;
for (i = tab->entries_start; i < tab->entries_bound; i++) {
@@ -2188,10 +2221,11 @@ st_rehash_indexed(st_table *tab)
{
int eq_p, rebuilt_p;
st_index_t i;
- st_index_t const n = bins_size(tab);
+
+ if (!tab->bins) {
+ tab->bins = malloc(bins_size(tab));
+ }
unsigned int const size_ind = get_size_ind(tab);
- st_index_t *bins = realloc(tab->bins, n);
- tab->bins = bins;
initialize_bins(tab);
for (i = tab->entries_start; i < tab->entries_bound; i++) {
st_table_entry *p = &tab->entries[i];
@@ -2207,10 +2241,10 @@ st_rehash_indexed(st_table *tab)
ind = hash_bin(p->hash, tab);
for (;;) {
- st_index_t bin = get_bin(bins, size_ind, ind);
+ st_index_t bin = get_bin(tab->bins, size_ind, ind);
if (EMPTY_OR_DELETED_BIN_P(bin)) {
/* ok, new room */
- set_bin(bins, size_ind, ind, i + ENTRY_BASE);
+ set_bin(tab->bins, size_ind, ind, i + ENTRY_BASE);
break;
}
else {
@@ -2446,6 +2480,16 @@ set_make_tab_empty(set_table *tab)
set_initialize_bins(tab);
}
+static inline size_t
+set_entries_memsize(set_table *tab)
+{
+ size_t memsize = set_get_allocated_entries(tab) * sizeof(set_table_entry);
+ if (set_has_bins(tab)) {
+ memsize += set_bins_size(tab);
+ }
+ return memsize;
+}
+
static set_table *
set_init_existing_table_with_size(set_table *tab, const struct st_hash_type *type, st_index_t size)
{
@@ -2471,12 +2515,7 @@ set_init_existing_table_with_size(set_table *tab, const struct st_hash_type *typ
tab->bin_power = features[n].bin_power;
tab->size_ind = features[n].size_ind;
- size_t memsize = 0;
- if (set_has_bins(tab)) {
- memsize += set_bins_size(tab);
- }
- memsize += set_get_allocated_entries(tab) * sizeof(set_table_entry);
- tab->entries = (set_table_entry *)malloc(memsize);
+ tab->entries = (set_table_entry *)malloc(set_entries_memsize(tab));
set_make_tab_empty(tab);
tab->rebuilds_num = 0;
return tab;
@@ -2526,8 +2565,8 @@ set_table_clear(set_table *tab)
void
set_free_table(set_table *tab)
{
- free(tab->entries);
- free(tab);
+ sized_free(tab->entries, set_entries_memsize(tab));
+ free_fixed_ptr(tab);
}
/* Return byte size of memory allocated for table TAB. */
@@ -2625,12 +2664,14 @@ set_rebuild_table_with(set_table *const new_tab, set_table *const tab)
static void
set_rebuild_move_table(set_table *const new_tab, set_table *const tab)
{
+ sized_free(tab->entries, set_entries_memsize(tab));
+ tab->entries = new_tab->entries;
+
tab->entry_power = new_tab->entry_power;
tab->bin_power = new_tab->bin_power;
tab->size_ind = new_tab->size_ind;
- free(tab->entries);
- tab->entries = new_tab->entries;
- free(new_tab);
+
+ free_fixed_ptr(new_tab);
}
static void