Marshal.load: do not call the proc until strings have their encoding

Ref: https://bugs.ruby-lang.org/issues/18141
This commit is contained in:
Jean Boussier 2021-09-01 09:43:39 +01:00 committed by Nobuyoshi Nakada
parent a0357acf19
commit 89242279e6
Notes: git 2021-09-15 08:00:43 +09:00
3 changed files with 61 additions and 19 deletions

View File

@ -1690,6 +1690,9 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
v = r_object0(arg, &ivar, extmod); v = r_object0(arg, &ivar, extmod);
if (ivar) r_ivar(v, NULL, arg); if (ivar) r_ivar(v, NULL, arg);
if (RB_TYPE_P(v, T_STRING)) {
v = r_leave(v, arg);
}
} }
break; break;
@ -1819,7 +1822,9 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
case TYPE_STRING: case TYPE_STRING:
v = r_entry(r_string(arg), arg); v = r_entry(r_string(arg), arg);
if (!ivp) {
v = r_leave(v, arg); v = r_leave(v, arg);
}
break; break;
case TYPE_REGEXP: case TYPE_REGEXP:

View File

@ -20,6 +20,24 @@ describe :marshal_load, shared: true do
end end
describe "when called with a proc" do describe "when called with a proc" do
ruby_bug "#18141", ""..."3.1" do
it "call the proc with fully initialized strings" do
utf8_string = "foo".encode(Encoding::UTF_8)
Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
if arg.is_a?(String)
arg.should == utf8_string
arg.encoding.should == Encoding::UTF_8
end
arg
})
end
it "no longer mutate the object after it was passed to the proc" do
string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
string.should.frozen?
end
end
it "returns the value of the proc" do it "returns the value of the proc" do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4] Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end end
@ -35,6 +53,7 @@ describe :marshal_load, shared: true do
ret.size.should == 3 ret.size.should == 3
end end
ruby_bug "#18141", ""..."3.1" do
it "loads an Array with proc" do it "loads an Array with proc" do
arr = [] arr = []
s = 'hi' s = 'hi'
@ -52,12 +71,13 @@ describe :marshal_load, shared: true do
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) 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, arr.should == [false, 5, "hi", 10, "hi", "hi", 0.0, st, false, "none",
:b, :c, a, 2, ["hi", 10, "hi", "hi", st, [:a, :b, :c]], "ant", false] :b, :c, a, 2, ["hi", 10, "hi", "hi", st, [:a, :b, :c]], false, "ant"]
Struct.send(:remove_const, :Brittle) Struct.send(:remove_const, :Brittle)
end end
end end
end
describe "when called with nil for the proc argument" do describe "when called with nil for the proc argument" do
it "behaves as if no proc argument was passed" do it "behaves as if no proc argument was passed" do

View File

@ -676,6 +676,23 @@ class TestMarshal < Test::Unit::TestCase
assert_equal(['X', 'X'], Marshal.load(Marshal.dump(obj), ->(v) { v == str ? v.upcase : v })) assert_equal(['X', 'X'], Marshal.load(Marshal.dump(obj), ->(v) { v == str ? v.upcase : v }))
end end
def test_marshal_proc_string_encoding
string = "foo"
payload = Marshal.dump(string)
Marshal.load(payload, ->(v) {
if v.is_a?(String)
assert_equal(string, v)
assert_equal(string.encoding, v.encoding)
end
v
})
end
def test_marshal_proc_freeze
object = { foo: [42, "bar"] }
assert_equal object, Marshal.load(Marshal.dump(object), :freeze.to_proc)
end
def test_marshal_load_extended_class_crash def test_marshal_load_extended_class_crash
assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
begin; begin;