Project

General

Profile

Actions

Bug #18428

closed

Calling Object#singleton_class mutates object's class from the C API's perspective

Added by antstorm (Anthony Dmitriyev) over 2 years ago. Updated over 2 years ago.

Status:
Rejected
Assignee:
-
Target version:
-
ruby -v:
ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [arm64-darwin20]
[ruby-core:106783]

Description

Hi,

I'm not 100% sure if this is an actual bug, but it feels like it. When a Object#singleton_class method is called on an object it swaps the object's class with a singleton's class (as far as CLASS_OF C call is concerned).

Here's a simple example to reproduce the issue:

  1. The C extension that adds a #c_class method to the Object, returning back the value of CLASS_OF call
#include "ruby.h"
#include "extconf.h"

static VALUE c_class(VALUE self) {
  return CLASS_OF(self);
}

void Init_c_class(void) {
  rb_define_method(rb_cObject, "c_class", c_class, 0);
}
  1. With that extension required, we can expose the issue from the console:
>> a = 'test'
=> "test"
>> a.class
=> String
>> a.c_class
=> String
>> a.singleton_class
=> #<Class:#<String:0x00000001168372e8>>
>> a.class
=> String
>> a.c_class
=> #<Class:#<String:0x00000001168372e8>>

I would expect the last call to c_class to return the same value as previously — String, instead it returns a singleton class.

Originally noticed this behaviour when passing a string to Google protobuf generated files, which raises this error — https://github.com/protocolbuffers/protobuf/blob/master/ruby/ext/google/protobuf_c/convert.c#L161. If the string had singleton_class called on it this would raise.

Updated by ufuk (Ufuk Kayserilioglu) over 2 years ago

This is by design, that's how singleton classes work. The singleton class subclasses from the original class and becomes the class of the object itself. The Ruby class method skips the singleton class and exposes the original class instead.

Updated by jeremyevans0 (Jeremy Evans) over 2 years ago

  • Status changed from Open to Rejected

antstorm (Anthony Dmitriyev) wrote:

I'm not 100% sure if this is an actual bug, but it feels like it. When a Object#singleton_class method is called on an object it swaps the object's class with a singleton's class (as far as CLASS_OF C call is concerned).

This is expected and not a bug, it's how singleton classes are implemented internally. You probably want to use rb_obj_class if you don't want the singleton class.

Originally noticed this behaviour when passing a string to Google protobuf generated files, which raises this error — https://github.com/protocolbuffers/protobuf/blob/master/ruby/ext/google/protobuf_c/convert.c#L161. If the string had singleton_class called on it this would raise.

That looks like a bug in protobuf, which they should fix.

Updated by antstorm (Anthony Dmitriyev) over 2 years ago

Ah, I see, that makes sense. Thank you for the quick response!

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0