ruby-changes:31878
From: glass <ko1@a...>
Date: Mon, 2 Dec 2013 21:59:40 +0900 (JST)
Subject: [ruby-changes:31878] glass:r43957 (trunk): * hash.c (rb_hash_rehash): make temporary st_table under the control
glass 2013-12-02 21:59:31 +0900 (Mon, 02 Dec 2013) New Revision: 43957 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=43957 Log: * hash.c (rb_hash_rehash): make temporary st_table under the control of GC. [Bug #9187] * test/ruby/test_hash.rb: add a test for above. Modified files: trunk/ChangeLog trunk/hash.c trunk/test/ruby/test_hash.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 43956) +++ ChangeLog (revision 43957) @@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Mon Dec 2 21:49:19 2013 Masaki Matsushita <glass.saga@g...> + + * hash.c (rb_hash_rehash): make temporary st_table under the control + of GC. [Bug #9187] + + * test/ruby/test_hash.rb: add a test for above. + Mon Dec 2 17:23:00 2013 Charlie Somerville <charliesome@r...> * variable.c (rb_mod_constants): when calling Module#constants with Index: hash.c =================================================================== --- hash.c (revision 43956) +++ hash.c (revision 43957) @@ -590,14 +590,6 @@ rb_hash_rehash_i(VALUE key, VALUE value, https://github.com/ruby/ruby/blob/trunk/hash.c#L590 return ST_CONTINUE; } -static VALUE -rehash_func(VALUE arg) -{ - struct rehash_arg *p = (struct rehash_arg *)arg; - rb_hash_foreach(p->hash, rb_hash_rehash_i, (VALUE)p->tbl); - return Qnil; -} - /* * call-seq: * hsh.rehash -> hsh @@ -621,30 +613,23 @@ rehash_func(VALUE arg) https://github.com/ruby/ruby/blob/trunk/hash.c#L613 static VALUE rb_hash_rehash(VALUE hash) { - int state; - struct rehash_arg arg; - st_table *new_tbl, *old_tbl = RHASH(hash)->ntbl; + VALUE tmp; + st_table *tbl; if (RHASH_ITER_LEV(hash) > 0) { rb_raise(rb_eRuntimeError, "rehash during iteration"); } rb_hash_modify_check(hash); - if (!old_tbl) return hash; - - new_tbl = st_init_table_with_size(old_tbl->type, old_tbl->num_entries); - arg.hash = hash; - arg.tbl = new_tbl; - - rb_protect(rehash_func, (VALUE)&arg, &state); - - if (state) { - st_free_table(new_tbl); - rb_jump_tag(state); - } - else { - st_free_table(RHASH(hash)->ntbl); - RHASH(hash)->ntbl = new_tbl; - } + if (!RHASH(hash)->ntbl) + return hash; + tmp = rb_hash_new(); + tbl = st_init_table_with_size(RHASH(hash)->ntbl->type, RHASH(hash)->ntbl->num_entries); + RHASH(tmp)->ntbl = tbl; + + rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl); + st_free_table(RHASH(hash)->ntbl); + RHASH(hash)->ntbl = tbl; + RHASH(tmp)->ntbl = 0; return hash; } Index: test/ruby/test_hash.rb =================================================================== --- test/ruby/test_hash.rb (revision 43956) +++ test/ruby/test_hash.rb (revision 43957) @@ -1080,6 +1080,34 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1080 assert_not_equal([a,"hello"].hash, [b,"world"].hash, bug9151) end + def test_exception_in_rehash + bug9187 = '[ruby-core:58728] [Bug #9187]' + + prepare = <<-EOS + class Foo + def initialize + @raise = false + end + + def hash + raise if @raise + @raise = true + return 0 + end + end + EOS + + code = <<-EOS + h = {Foo.new => true} + 10_0000.times do + h.rehash rescue nil + end + GC.start + EOS + + assert_no_memory_leak([], prepare, code, bug9187) + end + class TestSubHash < TestHash class SubHash < Hash end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/