Skip to content

Resolve C superclass variables assigned from rb_const_get - #1861

Open
anyingiit wants to merge 1 commit into
ruby:masterfrom
anyingiit:c-superclass-rb-const-get
Open

anyingiit wants to merge 1 commit into
ruby:masterfrom
anyingiit:c-superclass-rb-const-get

Conversation

@anyingiit

Copy link
Copy Markdown
Contributor

Fixes #1782. When a C extension gets a class with rb_const_get and then reuses the same variable as both the superclass and the target of rb_define_class_under (as kgio does), the C parser recorded the superclass as the variable name "cSocket". Store#resolve_c_superclasses later resolved that variable to the class being defined, so Example::Socket became its own superclass. Since #1785 this no longer overflows the stack, but ri still shows Example::Socket < Example::Socket.

handle_class_module now looks up a superclass variable it doesn't already know. If it was assigned from rb_const_get(under, rb_intern("Name")) (or rb_const_get_at / rb_intern_const), it uses that class name: Name when under is rb_cObject, Under::Name for another known module. If the variable is assigned different constants in different places, the lookup gives up and keeps the variable name rather than guess. The issue's example now documents Example::Socket < Socket. The same lookup also fixes a plain rb_define_class("Foo", cBase) where cBase came from rb_const_get, which used to show the variable name as the superclass. With kgio's sources, Kgio::Socket, TCPSocket, TCPServer, UNIXSocket and UNIXServer now get their real superclasses. The superclasses documented for Ruby's own ext/*.c don't change.

As a safety net, resolve_c_superclasses no longer replaces a superclass with the class itself (the minimum suggested in the issue). Then an unresolvable variable stays a name rather than forming a cycle.

The first hunk touches the same line as #1831 (parent_name = ... in handle_class_module), so whichever lands second will need a small rebase. I'm happy to do it.

When a C extension reuses one variable as both the superclass argument
and the target of rb_define_class_under:

  VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
  cSocket = rb_define_class_under(mExample, "Socket", cSocket);

the C parser recorded the superclass as the variable name "cSocket".
Store#resolve_c_superclasses then resolved that variable to the class
being defined, so Example::Socket became its own superclass.

Look up a superclass variable that was assigned from
rb_const_get(under, rb_intern("Name")) and use that class name instead,
and never let resolve_c_superclasses make a class its own superclass.

Fixes ruby#1782
@github-actions

Copy link
Copy Markdown

Documentation preview

View the preview

Commit: 7fac2dd

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C parser creates a self-referencing superclass when rb_define_class_under reuses a C variable

1 participant