about summary refs log tree commit
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-09-20 18:43:19 -0700
committerEric Wong <normalperson@yhbt.net>2010-09-21 15:22:27 -0700
commit79f22da9c87d295bd39ea24250c2d64df8110cc9 (patch)
tree01af7450569d59e8e03129c5ed9f5f7c2f5189a1
parent489db03a546b3ee41760f1ee8d662fba81299b60 (diff)
downloadrpatricia-79f22da9c87d295bd39ea24250c2d64df8110cc9.tar.gz
fix segfault from unpredictable GC ordering
We cannot guarantee GC will mark valid nodes when the tree
the node belongs to is destroyed, so we have to allocate
a new node that is a copy of the original node whenever
we create Patricia::Node objects
-rw-r--r--ext/rpatricia/rpatricia.c9
-rw-r--r--test/test_old_segfaults.rb8
2 files changed, 14 insertions, 3 deletions
diff --git a/ext/rpatricia/rpatricia.c b/ext/rpatricia/rpatricia.c
index 1c81ba1..ae018af 100644
--- a/ext/rpatricia/rpatricia.c
+++ b/ext/rpatricia/rpatricia.c
@@ -33,10 +33,13 @@ p_node_mark (void *ptr)
 }
 
 static VALUE
-wrap_node(patricia_node_t *node)
+wrap_node(patricia_node_t *orig)
 {
-  /* node will be freed when parent is freed */
-  return Data_Wrap_Struct(cNode, p_node_mark, 0, node);
+  patricia_node_t *node = ALLOC(patricia_node_t);
+
+  memcpy(node, orig, sizeof(patricia_node_t));
+
+  return Data_Wrap_Struct(cNode, p_node_mark, -1, node);
 }
 
 static prefix_t *
diff --git a/test/test_old_segfaults.rb b/test/test_old_segfaults.rb
index 5e7ec3e..96f1b43 100644
--- a/test/test_old_segfaults.rb
+++ b/test/test_old_segfaults.rb
@@ -30,4 +30,12 @@ class TestOldSegfaults < Test::Unit::TestCase
     t = Patricia.new
     assert_equal 0, t.num_nodes
   end
+
+  def test_gc_ordering_segfault
+    added = []
+    100000.times do
+      tmp = Patricia.new
+      added << tmp.add('8.8.8.8')
+    end
+  end
 end