Bug #18141
Updated by byroot (Jean Boussier) about 3 years ago
I assume this is a bug because I can't find any spec or test for this behaviour: Consider the following script: ```ruby payload = Marshal.dump("foo") Marshal.load(payload, -> (obj) { if obj.is_a?(String) p [obj, obj.encoding] end obj }) p [:final, string, string.encoding] ``` outputs: ```ruby ["foo", #<Encoding:ASCII-8BIT>] [:final, "foo", #<Encoding:UTF-8>] ``` So `Marshal` call the proc before the string get its encoding assigned, this is because the encoding is stored alongside as a `TYPE_IVAR`. I think in such cases `Marshal` should delay calling the proc until the object is fully restored. A corollary to this behaviour is that the following code: ```ruby Marshal.load(payload, :freeze.to_proc) ``` raises with `can't modify frozen String: "foo" (FrozenError)`. The same happens with any instance variable on `Array` or `Hash` ```ruby foo = {} foo.instance_variable_set(:@bar, 42) payload = Marshal.dump(foo) object = Marshal.load(payload, ->(obj) { if obj.is_a?(Hash) p [obj, obj.instance_variable_get(:@bar)] obj.freeze end obj }) ``` ``` [{}, nil] /tmp/marshal.rb:6:in `load': can't modify frozen Hash: {} (FrozenError) from /tmp/marshal.rb:6:in `<main> ```