Environment Information
JRuby:
$ jruby -v
jruby 10.1.0.0 (4.0.0) 2026-04-20 32f988b78c OpenJDK 64-Bit Server VM 26+35 on 26+35 +indy +jit [x86_64-linux]
MRI comparison:
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [x86_64-linux]
Expected Behavior
Marshal.load(Marshal.dump(obj)) should preserve repeated object references correctly. In the script below, loaded[2] should be "good".
Repro:
require 'set'
shared = 'good'
payload = [
Set.new,
['bad', shared],
shared,
]
loaded = Marshal.load(Marshal.dump(payload))
puts RUBY_DESCRIPTION
puts "expected: good"
puts "actual: #{loaded[2].inspect}"
puts "ok: #{loaded[2] == 'good'}"
MRI output:
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [x86_64-linux]
expected: good
actual: "good"
ok: true
Actual Behavior
JRuby 10.1.0.0 output:
jruby 10.1.0.0 (4.0.0) 2026-04-20 32f988b78c OpenJDK 64-Bit Server VM 26+35 on 26+35 +indy +jit [x86_64-linux]
expected: good
actual: "bad"
ok: false
The third element of the top-level array becomes "bad" after the Marshal roundtrip. It should remain the same string object/value as shared, i.e. "good".
Some narrowing observations:
- No threading is involved.
- The issue reproduces with plain Marshal.dump / Marshal.load.
- Replacing
Set.new with [] or {} avoids the problem.
- Using shared.dup for the third payload element avoids the problem.
- The failure seems to require a Set appearing before a nested array containing a shared string object that is referenced again later.
This was found while debugging Opal's compiler cache on JRuby 10.1.0.0 (a regression since JRuby 10.0.2.0), where a cached compiler's generated JavaScript string was replaced by a source-map mappings string after a Marshal roundtrip.
Ref: opal/opal#2787
Environment Information
JRuby:
MRI comparison:
Expected Behavior
Marshal.load(Marshal.dump(obj))should preserve repeated object references correctly. In the script below,loaded[2]should be"good".Repro:
MRI output:
Actual Behavior
JRuby 10.1.0.0 output:
The third element of the top-level array becomes
"bad"after the Marshal roundtrip. It should remain the same string object/value as shared, i.e."good".Some narrowing observations:
Set.newwith[]or{}avoids the problem.This was found while debugging Opal's compiler cache on JRuby 10.1.0.0 (a regression since JRuby 10.0.2.0), where a cached compiler's generated JavaScript string was replaced by a source-map mappings string after a Marshal roundtrip.
Ref: opal/opal#2787