summaryrefslogtreecommitdiff
path: root/internal/class.h
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 20:31:23 -0700
commitad729a1d11c6c57efd2e92803b4e937db0f75252 (patch)
tree572c79bde61b62de8728ca6d81e3c6dcfbe94d1a /internal/class.h
parentfdb31aa7ab1bb1718e57e2e052caff959af3111e (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 change caused a VM assertion failure, which was traced to callable method entries using the incorrect defined_class. Update rb_vm_check_redefinition_opt_method and find_defined_class_by_owner to treat iclass origins different than class origins to avoid this issue. 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/3136
Diffstat (limited to 'internal/class.h')
-rw-r--r--internal/class.h10
1 files changed, 9 insertions, 1 deletions
diff --git a/internal/class.h b/internal/class.h
index 4bebb22905..7724fe43a6 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -95,9 +95,10 @@ typedef struct rb_classext_struct rb_classext_t;
#endif
#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
-#define RCLASS_CLONED FL_USER6
#define RICLASS_IS_ORIGIN FL_USER5
+#define RCLASS_CLONED FL_USER6
#define RCLASS_REFINED_BY_ANY FL_USER7
+#define RICLASS_ORIGIN_SHARED_MTBL FL_USER8
/* class.c */
void rb_class_subclass_add(VALUE super, VALUE klass);
@@ -120,6 +121,7 @@ VALUE rb_singleton_class_get(VALUE obj);
int rb_class_has_methods(VALUE c);
void rb_undef_methods_from(VALUE klass, VALUE super);
static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
+static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass);
static inline VALUE RCLASS_SUPER(VALUE klass);
static inline VALUE RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
@@ -137,6 +139,12 @@ RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
}
static inline void
+RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass)
+{
+ FL_SET(iclass, RICLASS_ORIGIN_SHARED_MTBL);
+}
+
+static inline void
RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass)
{
RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass);