summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2020-04-05 12:10:42 -0700
committerJeremy Evans <code@jeremyevans.net>2020-05-22 07:36:52 -0700
commitc745a60634260ba2080d35af6fdeaaae86fe5193 (patch)
treeb0b3a34af7c2847940dc294408a763535d1861c5 /gc.c
parentef13558fcd99dc2057cbfc0973f9592f0f8b3071 (diff)
Fix origin iclass pointer for modules
If a module has an origin, and that module is included in another module or class, previously the iclass created for the module had an origin pointer to the module's origin instead of the iclass's origin. Setting the origin pointer correctly requires using a stack, since the origin iclass is not created until after the iclass itself. Use a hidden ruby array to implement that stack. Correctly assigning the origin pointers in the iclass caused a use-after-free in GC. If a module with an origin is included in a class, the iclass shares a method table with the module and the iclass origin shares a method table with module origin. Mark iclass origin with a flag that notes that even though the iclass is an origin, it shares a method table, so the method table should not be garbage collected. The shared method table will be garbage collected when the module origin is garbage collected. I've tested that this does not introduce a memory leak. This also includes a fix for Module#included_modules to skip iclasses with origins. Fixes [Bug #16736]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2978
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/gc.c b/gc.c
index b0fa670e9e..9674d678e7 100644
--- a/gc.c
+++ b/gc.c
@@ -2815,9 +2815,11 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
break;
case T_ICLASS:
/* Basically , T_ICLASS shares table with the module */
- if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
- rb_id_table_free(RCLASS_M_TBL(obj));
- }
+ if (FL_TEST(obj, RICLASS_IS_ORIGIN) &&
+ !FL_TEST(obj, RICLASS_ORIGIN_SHARED_MTBL)) {
+ /* Method table is not shared for origin iclasses of classes */
+ rb_id_table_free(RCLASS_M_TBL(obj));
+ }
if (RCLASS_CALLABLE_M_TBL(obj) != NULL) {
rb_id_table_free(RCLASS_CALLABLE_M_TBL(obj));
}
@@ -3911,7 +3913,8 @@ obj_memsize_of(VALUE obj, int use_all_types)
}
break;
case T_ICLASS:
- if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
+ if (FL_TEST(obj, RICLASS_IS_ORIGIN) &&
+ !FL_TEST(obj, RICLASS_ORIGIN_SHARED_MTBL)) {
if (RCLASS_M_TBL(obj)) {
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
@@ -5432,7 +5435,8 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
break;
case T_ICLASS:
- if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
+ if (FL_TEST(obj, RICLASS_IS_ORIGIN) &&
+ !FL_TEST(obj, RICLASS_ORIGIN_SHARED_MTBL)) {
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
}
if (RCLASS_SUPER(obj)) {
@@ -8296,7 +8300,8 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
break;
case T_ICLASS:
- if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
+ if (FL_TEST(obj, RICLASS_IS_ORIGIN) &&
+ !FL_TEST(obj, RICLASS_ORIGIN_SHARED_MTBL)) {
update_m_tbl(objspace, RCLASS_M_TBL(obj));
}
if (RCLASS_SUPER((VALUE)obj)) {