Skip to content

Commit 21f9032

Browse files
committed
[GR-23797] Update Marshal.dump to raise an error when an object has singleton methods
PullRequest: truffleruby/3263
2 parents 8156769 + ef1ec8f commit 21f9032

File tree

5 files changed

+29
-1
lines changed

5 files changed

+29
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Bug fixes:
99

1010
Compatibility:
1111

12+
* Fix `Marshal.dump` to raise an error when an object has singleton methods (@bjfish).
1213

1314
Performance:
1415

spec/tags/core/marshal/dump_tags.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
fails:Marshal.dump with an Object raises if an Object has a singleton class and singleton methods
21
fails(immutable regexp):Marshal.dump with a Regexp dumps a Regexp with instance variables
32
fails(immutable regexp):Marshal.dump with a Regexp dumps an extended Regexp
43
fails(immutable regexp):Marshal.dump with a Regexp dumps a Regexp subclass

src/main/java/org/truffleruby/core/kernel/KernelNodes.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,24 @@ protected RubyArray singletonMethods(Object self, boolean includeAncestors,
16291629

16301630
}
16311631

1632+
@Primitive(name = "singleton_methods?")
1633+
public abstract static class HasSingletonMethodsNode extends PrimitiveArrayArgumentsNode {
1634+
1635+
@TruffleBoundary
1636+
@Specialization
1637+
protected boolean hasSingletonMethods(Object self,
1638+
@Cached MetaClassNode metaClassNode) {
1639+
final RubyClass metaClass = metaClassNode.execute(self);
1640+
1641+
if (!metaClass.isSingleton) {
1642+
return false;
1643+
}
1644+
1645+
return metaClass.fields.anyMethodDefined();
1646+
}
1647+
1648+
}
1649+
16321650
@NodeChild(value = "duration", type = RubyBaseNodeWithExecute.class)
16331651
@CoreMethod(names = "sleep", isModuleFunction = true, optional = 1)
16341652
public abstract static class SleepNode extends CoreMethodNode {

src/main/java/org/truffleruby/core/module/ModuleFields.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,15 @@ public Collection<RubySymbol> filterMethods(
10471047
return filtered;
10481048
}
10491049

1050+
public boolean anyMethodDefined() {
1051+
for (var value : methods.values()) {
1052+
if (value.getMethod() != null) {
1053+
return true;
1054+
}
1055+
}
1056+
return false;
1057+
}
1058+
10501059
private Map<String, InternalMethod> getInternalMethodMap() {
10511060
Map<String, InternalMethod> map = new HashMap<>();
10521061
for (Entry<String, MethodEntry> e : methods.entrySet()) {

src/main/ruby/truffleruby/core/marshal.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ def serialize(obj)
10131013
end
10141014

10151015
def serialize_extended_object(obj)
1016+
raise TypeError, "singleton can't be dumped" if Primitive.singleton_methods?(obj)
10161017
str = +''
10171018
Primitive.vm_extended_modules obj, -> mod do
10181019
str << "e#{serialize(mod.name.to_sym)}"

0 commit comments

Comments
 (0)