Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 40040f995683
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8d7cba8fbf92
Choose a head ref
  • 3 commits
  • 3 files changed
  • 1 contributor

Commits on Mar 2, 2015

  1. Added new Marshal.load spec for object with user-defined _dump

    Spec covers another edge case.
    sshao committed Mar 2, 2015
    Copy the full SHA
    ddacb4b View commit details
  2. Fixed Marshal again for objects whose _dump returns an immediate.

    specs behind this change: 58631d4
    sshao committed Mar 2, 2015
    Copy the full SHA
    363bb78 View commit details
  3. Copy the full SHA
    8d7cba8 View commit details
Showing with 88 additions and 66 deletions.
  1. +1 −1 kernel/common/marshal.rb
  2. +84 −62 spec/ruby/core/marshal/shared/load.rb
  3. +3 −3 spec/tags/ruby/core/marshal/load_tags.txt
2 changes: 1 addition & 1 deletion kernel/common/marshal.rb
Original file line number Diff line number Diff line change
@@ -465,7 +465,7 @@ def add_non_immediate_object(obj)
end

def add_object(obj)
sz = @links.size
sz = @objects.size
@objects[sz] = obj
@links[obj.__id__] = sz
end
146 changes: 84 additions & 62 deletions spec/ruby/core/marshal/shared/load.rb
Original file line number Diff line number Diff line change
@@ -20,62 +20,105 @@
lambda { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
end

it "returns the value of the proc when called with a proc" do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end
describe "when called with a proc" do
it "returns the value of the proc" do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end

it "calls the proc for recursively visited data" do
a = [1]
a << a
ret = []
Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg; arg })
ret.first.should == 1
ret[1].should == [1,a]
ret[2].should == a
ret.size.should == 3
end
it "calls the proc for recursively visited data" do
a = [1]
a << a
ret = []
Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg; arg })
ret.first.should == 1
ret[1].should == [1,a]
ret[2].should == a
ret.size.should == 3
end

it "loads an array containing objects having _dump method, and with proc" do
arr = []
myproc = Proc.new { |o| arr << o; o }
o1 = UserDefined.new;
o2 = UserDefinedWithIvar.new
obj = [o1, o2, o1, o2]
it "loads an Array with proc" do
arr = []
s = 'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o; o}

Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)

arr.should == [o1, o2, o1, o2, obj]
arr.should == ["hi", false, 5, 10, "hi", "hi", 0.0, st, "none", false,
:b, :c, a, 2, ["hi", 10, "hi", "hi", st, [:a, :b, :c]], "ant", false]
end
end

it "loads an array containing an object with _dump that returns an immediate value, followed by multiple instances of another object" do
str = "string"
describe "when called on objects with custom _dump methods" do
it "does not set instance variables of an object with user-defined _dump/_load" do
# this string represents: <#UserPreviouslyDefinedWithInitializedIvar @field2=7 @field1=6>
dump_str = "\004\bu:-UserPreviouslyDefinedWithInitializedIvar\a:\f@field2i\f:\f@field1i\v"

marshaled_obj = Marshal.send(@method, "\004\b[\bu:\031UserDefinedImmediate\000\"\vstring@\a")
UserPreviouslyDefinedWithInitializedIvar.should_receive(:_load).and_return(UserPreviouslyDefinedWithInitializedIvar.new)
marshaled_obj = Marshal.send(@method, dump_str)

marshaled_obj.should == [nil, str, str]
end
marshaled_obj.should be_an_instance_of(UserPreviouslyDefinedWithInitializedIvar)
marshaled_obj.field1.should be_nil
marshaled_obj.field2.should be_nil
end

describe "that return an immediate value" do
it "loads an array containing an instance of the object, followed by multiple instances of another object" do
str = "string"

# this string represents: [<#UserDefinedImmediate A>, <#String "string">, <#String "string">]
marshaled_obj = Marshal.send(@method, "\004\b[\bu:\031UserDefinedImmediate\000\"\vstring@\a")

marshaled_obj.should == [nil, str, str]
end

it "loads any structure with multiple references to an object with _dump that returns an immediate value" do
array_dump = "\004\b[\au:\031UserDefinedImmediate\000@\006"
hash_dump = "\004\b{\a:\006bu:\031UserDefinedImmediate\000:\006a@\006"
it "loads any structure with multiple references to the same object, followed by multiple instances of another object" do
str = "string"

marshaled_obj = Marshal.send(@method, hash_dump)
marshaled_obj.should == {:a => nil, :b => nil}
# this string represents: {:a => <#UserDefinedImmediate A>, :b => <#UserDefinedImmediate A>, :c => <#String "string">, :d => <#String "string">}
hash_dump = "\x04\b{\t:\x06aIu:\x19UserDefinedImmediate\x00\x06:\x06ET:\x06b@\x06:\x06cI\"\vstring\x06;\aT:\x06d@\a"

marshaled_obj = Marshal.send(@method, array_dump)
marshaled_obj.should == [nil, nil]
marshaled_obj = Marshal.send(@method, hash_dump)
marshaled_obj.should == {:a => nil, :b => nil, :c => str, :d => str}

# this string represents: [<#UserDefinedImmediate A>, <#UserDefinedImmediate A>, <#String "string">, <#String "string">]
array_dump = "\x04\b[\tIu:\x19UserDefinedImmediate\x00\x06:\x06ET@\x06I\"\vstring\x06;\x06T@\a"

marshaled_obj = Marshal.send(@method, array_dump)
marshaled_obj.should == [nil, nil, str, str]
end

it "loads an array containing references to multiple instances of the object, followed by multiple instances of another object" do
str = "string"

# this string represents: [<#UserDefinedImmediate A>, <#UserDefinedImmediate B>, <#String "string">, <#String "string">]
array_dump = "\x04\b[\tIu:\x19UserDefinedImmediate\x00\x06:\x06ETIu;\x00\x00\x06;\x06TI\"\vstring\x06;\x06T@\b"

marshaled_obj = Marshal.send(@method, array_dump)
marshaled_obj.should == [nil, nil, str, str]
end
end
end

it "does not set instance variables of an object with user-defined _dump/_load" do
# this string represents: <#UserPreviouslyDefinedWithInitializedIvar @field2=7 @field1=6>
dump_str = "\004\bu:-UserPreviouslyDefinedWithInitializedIvar\a:\f@field2i\f:\f@field1i\v"
it "loads an array containing objects having _dump method, and with proc" do
arr = []
myproc = Proc.new { |o| arr << o; o }
o1 = UserDefined.new;
o2 = UserDefinedWithIvar.new
obj = [o1, o2, o1, o2]

UserPreviouslyDefinedWithInitializedIvar.should_receive(:_load).and_return(UserPreviouslyDefinedWithInitializedIvar.new)
marshaled_obj = Marshal.send(@method, dump_str)
Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)

marshaled_obj.should be_an_instance_of(UserPreviouslyDefinedWithInitializedIvar)
marshaled_obj.field1.should be_nil
marshaled_obj.field2.should be_nil
arr.should == [o1, o2, o1, o2, obj]
end

it "loads an array containing objects having marshal_dump method, and with proc" do
@@ -90,27 +133,6 @@
arr.should == ['stuff', o1, 'my data', ['my data'], o2, o1, o2, obj]
end

it "loads an Array with proc" do
arr = []
s = 'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
st.a = 0.0
h = Hash.new('def')
h['nine'] = 9
a = [:a, :b, :c]
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
proc = Proc.new { |o| arr << o; o}

Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)

arr.should == ["hi", false, 5, 10, "hi", "hi", 0.0, st, "none", false,
:b, :c, a, 2, ["hi", 10, "hi", "hi", st, [:a, :b, :c]], "ant", false]
end

it "assigns classes to nested subclasses of Array correctly" do
arr = ArraySub.new(ArraySub.new)
arr_dump = Marshal.dump(arr)
6 changes: 3 additions & 3 deletions spec/tags/ruby/core/marshal/load_tags.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
fails:Marshal.load returns the value of the proc when called with a proc
fails:Marshal.load calls the proc for recursively visited data
fails:Marshal.load when called with a proc returns the value of the proc
fails:Marshal.load when called with a proc calls the proc for recursively visited data
fails:Marshal.load loads an array containing objects having _dump method, and with proc
fails:Marshal.load loads an array containing objects having marshal_dump method, and with proc
fails:Marshal.load loads an Array with proc
fails:Marshal.load when called with a proc loads an Array with proc
fails:Marshal.load returns an untrusted object if source is untrusted
fails:Marshal.load loads a Random
fails:Marshal.load for a user Class raises ArgumentError if the object from an 'o' stream is not dumpable as 'o' type user class