Skip to content

Commit 055fef0

Browse files
jhawthornbyroot
authored andcommitted
Free after insert in generic_ivar_set_shape_fields
Previously we were performing a realloc and then inserting the new value into the table. If the table was flagged as requiring a rebuild, this could trigger GC work and marking within that GC could access the fields freed by realloc.
1 parent 8aac19d commit 055fef0

1 file changed

Lines changed: 20 additions & 9 deletions

File tree

variable.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,12 +1227,6 @@ gen_fields_tbl_bytes(size_t n)
12271227
return offsetof(struct gen_fields_tbl, as.shape.fields) + n * sizeof(VALUE);
12281228
}
12291229

1230-
static struct gen_fields_tbl *
1231-
gen_fields_tbl_resize(struct gen_fields_tbl *old, uint32_t new_capa)
1232-
{
1233-
RUBY_ASSERT(new_capa > 0);
1234-
return xrealloc(old, gen_fields_tbl_bytes(new_capa));
1235-
}
12361230

12371231
void
12381232
rb_mark_generic_ivar(VALUE obj)
@@ -1837,13 +1831,28 @@ generic_ivar_set_shape_fields(VALUE obj, void *data)
18371831
int existing = st_lookup(tbl, (st_data_t)obj, (st_data_t *)&fields_tbl);
18381832

18391833
if (!existing || fields_lookup->resize) {
1834+
uint32_t new_capa = RSHAPE_CAPACITY(fields_lookup->shape_id);
1835+
uint32_t old_capa = RSHAPE_CAPACITY(RSHAPE_PARENT(fields_lookup->shape_id));
1836+
18401837
if (existing) {
18411838
RUBY_ASSERT(RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(fields_lookup->shape_id, SHAPE_OBJ_ID));
1842-
RUBY_ASSERT(RSHAPE_CAPACITY(RSHAPE_PARENT(fields_lookup->shape_id)) < RSHAPE_CAPACITY(fields_lookup->shape_id));
1839+
RUBY_ASSERT(old_capa < new_capa);
1840+
RUBY_ASSERT(fields_tbl);
1841+
} else {
1842+
RUBY_ASSERT(!fields_tbl);
1843+
RUBY_ASSERT(old_capa == 0);
18431844
}
1845+
RUBY_ASSERT(new_capa > 0);
18441846

1845-
fields_tbl = gen_fields_tbl_resize(fields_tbl, RSHAPE_CAPACITY(fields_lookup->shape_id));
1847+
struct gen_fields_tbl *old_fields_tbl = fields_tbl;
1848+
fields_tbl = xmalloc(gen_fields_tbl_bytes(new_capa));
1849+
if (old_fields_tbl) {
1850+
memcpy(fields_tbl, old_fields_tbl, gen_fields_tbl_bytes(old_capa));
1851+
}
18461852
st_insert(tbl, (st_data_t)obj, (st_data_t)fields_tbl);
1853+
if (old_fields_tbl) {
1854+
xfree(old_fields_tbl);
1855+
}
18471856
}
18481857

18491858
if (fields_lookup->shape_id) {
@@ -2371,7 +2380,9 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
23712380
return;
23722381
}
23732382

2374-
new_fields_tbl = gen_fields_tbl_resize(0, RSHAPE_CAPACITY(dest_shape_id));
2383+
uint32_t dest_capa = RSHAPE_CAPACITY(dest_shape_id);
2384+
RUBY_ASSERT(dest_capa > 0);
2385+
new_fields_tbl = xmalloc(gen_fields_tbl_bytes(dest_capa));
23752386

23762387
VALUE *src_buf = obj_fields_tbl->as.shape.fields;
23772388
VALUE *dest_buf = new_fields_tbl->as.shape.fields;

0 commit comments

Comments
 (0)