summaryrefslogtreecommitdiff
path: root/st.c
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2022-10-15 15:40:47 +0900
committernagachika <nagachika@ruby-lang.org>2022-10-15 15:40:47 +0900
commit830fbb412b1c01f0a44b66a70b946d7e87feb6e5 (patch)
tree485268f73ab26859a18efb504f3c20dfd8f02027 /st.c
parent994b505ffb0bf9eb795525199b47697412a98abb (diff)
merge revision(s) 76bae60d9b967415c5930c2c5906e14c8362a6dd: [Backport #19038]
[Bug #19038] Fix corruption of generic_iv_tbl when compacting When the generic_iv_tbl is resized up, rebuild_table performs allocations that can trigger GC. If autocompaction is enabled, then moved objects are removed from and inserted into the generic_iv_tbl. This may cause another call to rebuild_table to resize the generic_iv_tbl. When returning back to the original rebuild_table, some of the data may be stale, causing the generic_iv_tbl to be corrupted. This commit changes rebuild_table to only read data from the st_table after the allocations have completed. Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com> --- st.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
Diffstat (limited to 'st.c')
-rw-r--r--st.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/st.c b/st.c
index 07a083abb0..fb36a452f5 100644
--- a/st.c
+++ b/st.c
@@ -703,34 +703,39 @@ count_collision(const struct st_hash_type *type)
static void
rebuild_table(st_table *tab)
{
- st_index_t i, ni, bound;
+ st_index_t i, ni;
unsigned int size_ind;
st_table *new_tab;
- st_table_entry *entries, *new_entries;
+ st_table_entry *new_entries;
st_table_entry *curr_entry_ptr;
st_index_t *bins;
st_index_t bin_ind;
- bound = tab->entries_bound;
- entries = tab->entries;
if ((2 * tab->num_entries <= get_allocated_entries(tab)
&& REBUILD_THRESHOLD * tab->num_entries > get_allocated_entries(tab))
|| tab->num_entries < (1 << MINIMAL_POWER2)) {
/* Compaction: */
tab->num_entries = 0;
- if (tab->bins != NULL)
- initialize_bins(tab);
- new_tab = tab;
- new_entries = entries;
+ if (tab->bins != NULL)
+ initialize_bins(tab);
+ new_tab = tab;
+ new_entries = tab->entries;
}
else {
+ /* This allocation could trigger GC and compaction. If tab is the
+ * gen_iv_tbl, then tab could have changed in size due to objects being
+ * freed and/or moved. Do not store attributes of tab before this line. */
new_tab = st_init_table_with_size(tab->type,
2 * tab->num_entries - 1);
new_entries = new_tab->entries;
}
+
ni = 0;
bins = new_tab->bins;
size_ind = get_size_ind(new_tab);
+ st_index_t bound = tab->entries_bound;
+ st_table_entry *entries = tab->entries;
+
for (i = tab->entries_start; i < bound; i++) {
curr_entry_ptr = &entries[i];
PREFETCH(entries + i + 1, 0);