Project

General

Profile

Bug #18141

Updated by byroot (Jean Boussier) over 2 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> 
 ```

Back