[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]