Freeze hash literals embedded in duphash instructions
Previously, these hash literals were not frozen, and thus could be modified by ObjectSpace, resulting in undesired behavior. Example: ```ruby require 'objspace' def a(b={0=>1,1=>4,2=>17}) b end p a ObjectSpace.each_object(Hash) do |a| a[3] = 8 if a.class == Hash && a[0] == 1 && a[1] == 4 && a[2] == 17 end p a ``` It may be desirable to hide such hashes from ObjectSpace, since they are internal, but I'm not sure how to do that. From: Jeremy Evans <code@jeremyevans.net> git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66464 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
f89238ec0d
commit
ec7b1e475b
@ -4026,6 +4026,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_ro
|
|||||||
|
|
||||||
hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
|
hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
|
||||||
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
|
rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
|
||||||
|
rb_hash_freeze(hash);
|
||||||
iseq_add_mark_object_compile_time(iseq, hash);
|
iseq_add_mark_object_compile_time(iseq, hash);
|
||||||
ADD_INSN1(ret, line, duphash, hash);
|
ADD_INSN1(ret, line, duphash, hash);
|
||||||
}
|
}
|
||||||
|
@ -283,6 +283,22 @@ class TestRubyLiteral < Test::Unit::TestCase
|
|||||||
assert_equal "literal", h["string"]
|
assert_equal "literal", h["string"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def frozen_hash_literal_arg
|
||||||
|
{0=>1,1=>4,2=>17}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_hash_literal_frozen
|
||||||
|
assert_not_include frozen_hash_literal_arg, 3
|
||||||
|
assert_raise(FrozenError) do
|
||||||
|
ObjectSpace.each_object(Hash) do |a|
|
||||||
|
if a.class == Hash and !a.default_proc and a.size == 3
|
||||||
|
a[3] = 8 if a[0] == 1 and a[1] == 4 and a[2] == 17
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_not_include frozen_hash_literal_arg, 3
|
||||||
|
end
|
||||||
|
|
||||||
def test_big_array_and_hash_literal
|
def test_big_array_and_hash_literal
|
||||||
assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).map{'x'}.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
|
assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).map{'x'}.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
|
||||||
assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).to_a.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
|
assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).to_a.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user