mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[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>
This commit is contained in:
parent
e696ec67ac
commit
76bae60d9b
Notes:
git
2022-10-06 22:01:35 +09:00
1 changed files with 10 additions and 5 deletions
15
st.c
15
st.c
|
@ -703,16 +703,14 @@ 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)) {
|
||||
|
@ -721,16 +719,23 @@ rebuild_table(st_table *tab)
|
|||
if (tab->bins != NULL)
|
||||
initialize_bins(tab);
|
||||
new_tab = tab;
|
||||
new_entries = entries;
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue