Fix generic_ivar_set_shape_field for table rebuild

[Bug #21438]

Previously GC could trigger a table rebuild of the generic fields
st_table in the middle of calling the st_update callback. This could
cause entries to be reallocated or rearranged and the update to be for
the wrong entry.

This commit adds an assertion to make that case easier to detect, and
replaces the st_update with a separate st_lookup and st_insert.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
This commit is contained in:
John Hawthorn 2025-06-13 18:52:32 -07:00
parent 74cdf8727e
commit 5342d9130b
Notes: git 2025-06-14 06:29:54 +00:00
3 changed files with 42 additions and 29 deletions

9
st.c
View file

@ -1495,7 +1495,16 @@ st_update(st_table *tab, st_data_t key,
value = entry->record;
}
old_key = key;
unsigned int rebuilds_num = tab->rebuilds_num;
retval = (*func)(&key, &value, arg, existing);
// We need to make sure that the callback didn't cause a table rebuild
// Ideally we would make sure no operations happened
assert(rebuilds_num == tab->rebuilds_num);
(void)rebuilds_num;
switch (retval) {
case ST_CONTINUE:
if (! existing) {