Project

General

Profile

Actions

Bug #19169

closed

Kernel#freeze doesn't propagate to singleton class when the singleton class has prepended modules

Added by alanwu (Alan Wu) over 1 year ago. Updated over 1 year ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.2.0dev (2022-12-01T16:50:48Z master 9da2a5204f) [arm64-darwin22]
[ruby-core:111138]

Description

a = []
singleton = a.singleton_class
a.freeze
p singleton.frozen? # => true

a = []
singleton = a.singleton_class.tap { |klass| klass.prepend(Module.new) }
a.freeze
p singleton.frozen? # => false

It's because of this function:

void
rb_freeze_singleton_class(VALUE x)
{
    /* should not propagate to meta-meta-class, and so on */
    if (!(RBASIC(x)->flags & FL_SINGLETON)) {
        VALUE klass = RBASIC_CLASS(x);
        if (klass && (klass = RCLASS_ORIGIN(klass)) != 0 &&
            FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) {
            OBJ_FREEZE_RAW(klass);
        }
    }
}

It freezes the origin class of the singleton class, but I'm not sure why.
When there is no prepended modules RCLASS_ORIGIN(klass) just returns klass.
It's old code, so maybe the meaning of RCLASS_ORIGIN has changed?

Practically speaking not a big deal because each time one calls .singleton_class
it copies the frozen bit of the attached object to the singleton class.

Updated by byroot (Jean Boussier) over 1 year ago

I ran it against older rubies, and it seems like it has been behaving like this since prepend was introduced.

It seem to work on TruffleRuby, but not JRuby.

Actions #2

Updated by alanwu (Alan Wu) over 1 year ago

  • Status changed from Open to Closed

Applied in changeset git|bb8afd7265af41a75e8889774aa26f157f146380.


Freeze singleton class, not its origin

Previously, when we froze an object, we froze
RCLASS_ORIGIN(object.singleton_class), which didn't freeze
object.singleton_class when it has some prepended modules.

Origin iclass are internal objects and users can't interact with
them through Kernel#freeze?, Kernel#freeze, or any mutation method
that checks the frozen status. So we shouldn't touch the origin
iclasses when the frozen status should be visible.

[Bug #19169]

Actions

Also available in: Atom PDF

Like0
Like0Like0