[#23457] [Bug #1471] "Mutual join" deadlock detection faulty in 1.8.6 and 1.8.7 — John Carter <redmine@...>

Bug #1471: "Mutual join" deadlock detection faulty in 1.8.6 and 1.8.7

17 messages 2009/05/15

[#23483] [Bug #1478] Ruby archive — Oleg Puchinin <redmine@...>

Bug #1478: Ruby archive

29 messages 2009/05/16
[#29225] [Feature #1478] Ruby archive — Luis Lavena <redmine@...> 2010/04/02

Issue #1478 has been updated by Luis Lavena.

[#30345] Re: [Feature #1478] Ruby archive — "NAKAMURA, Hiroshi" <nakahiro@...> 2010/05/21

On Fri, Apr 2, 2010 at 17:13, Luis Lavena <redmine@ruby-lang.org> wrote:

[#30346] Re: [Feature #1478] Ruby archive — Jonathan Nielsen <jonathan@...> 2010/05/21

> Thanks for your comment.

[#30347] Re: [Feature #1478] Ruby archive — Jonathan Nielsen <jonathan@...> 2010/05/21

OK Hiroshi, I read some of the comments earlier in the thread that I

[#30355] Re: [Feature #1478] Ruby archive — Caleb Clausen <vikkous@...> 2010/05/21

On 5/20/10, Jonathan Nielsen <jonathan@jmnet.us> wrote:

[#30364] Re: [Feature #1478] Ruby archive — Benoit Daloze <eregontp@...> 2010/05/22

Hi,

[#23505] [Bug #1494] tempfile#unlink may silently fail on windows — Nicholas Manning <redmine@...>

Bug #1494: tempfile#unlink may silently fail on windows

19 messages 2009/05/19

[#23572] [Bug #1525] Deadlock in Ruby 1.9's VM caused by ConditionVariable.wait and fork? — Hongli Lai <redmine@...>

Bug #1525: Deadlock in Ruby 1.9's VM caused by ConditionVariable.wait and fork?

27 messages 2009/05/27

[#23595] Meaning of RUBY_PLATFORM — Rick DeNatale <rick.denatale@...>

The RUBY_PLATFORM constant is documented in the latest Pickaxe as "The

17 messages 2009/05/28
[#23596] Re: Meaning of RUBY_PLATFORM — Luis Lavena <luislavena@...> 2009/05/28

On Thu, May 28, 2009 at 3:41 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:

[#23602] Re: Meaning of RUBY_PLATFORM — Rick DeNatale <rick.denatale@...> 2009/05/28

On Thu, May 28, 2009 at 2:52 PM, Luis Lavena <luislavena@gmail.com> wrote:

[#23608] Re: Meaning of RUBY_PLATFORM — Luis Lavena <luislavena@...> 2009/05/28

On Thu, May 28, 2009 at 7:08 PM, Rick DeNatale <rick.denatale@gmail.com> wrote:

[#23609] Re: Meaning of RUBY_PLATFORM — Rick DeNatale <rick.denatale@...> 2009/05/29

On Thu, May 28, 2009 at 7:22 PM, Luis Lavena <luislavena@gmail.com> wrote:

[ruby-core:23406] Re: [Bug #1448] [patch] Proper handling of recursive arrays

From: Nobuyoshi Nakada <nobu@...>
Date: 2009-05-09 07:02:03 UTC
List: ruby-core #23406
Hi,

At Sat, 9 May 2009 11:47:53 +0900,
Marc-Andre Lafortune wrote in [ruby-core:23402]:
> The attached patch fixes all of these problems :-)

But reverts old problems.

$ ./ruby -e 'x={};x[1]=x;y={};y[1]=y; p x==y'
-e:1:in `==': stack level too deep (SystemStackError)
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	 ... 5124 levels...
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `=='
	from -e:1:in `<main>'

Also, note that arg of rb_exec_recursive() is not restricted to
a real VALUE.

> * Last problem:
> There is one more problem that my patch doesn't cover (lack
> of mri-fu): hashes for recursive structures are incorrect. As
> per the official doc, "a.eql? b" should imply "a.hash ==
> b.hash". On the other hand, we have (before or after my
> patch):
> a = [x]
> x.eql? a  # ==> true
> a.eql? x  # ==> true
> x.hash == a.hash # ==> false, should have same hash

I wonder it may be false positive.

$ ruby -e 'x=[];x<<x;a=[x]; p a, x'
[[[...]]]
[[...]]

But no idea right now.

A patch based on yours.


Index: array.c
===================================================================
--- array.c	(revision 23373)
+++ array.c	(working copy)
@@ -2729,5 +2729,5 @@ recursive_equal(VALUE ary1, VALUE ary2, 
     long i;
 
-    if (recur) return Qfalse;
+    if (recur) return Qtrue; /* Subtle! */
     for (i=0; i<RARRAY_LEN(ary1); i++) {
 	if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
@@ -2762,5 +2762,5 @@ rb_ary_equal(VALUE ary1, VALUE ary2)
     }
     if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
-    return rb_exec_recursive(recursive_equal, ary1, ary2);
+    return rb_exec_recursive_paired(recursive_equal, ary1, ary2);
 }
 
@@ -2770,5 +2770,5 @@ recursive_eql(VALUE ary1, VALUE ary2, in
     long i;
 
-    if (recur) return Qfalse;
+    if (recur) return Qtrue; /* Subtle! */
     for (i=0; i<RARRAY_LEN(ary1); i++) {
 	if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
@@ -2792,5 +2792,5 @@ rb_ary_eql(VALUE ary1, VALUE ary2)
     if (TYPE(ary2) != T_ARRAY) return Qfalse;
     if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
-    return rb_exec_recursive(recursive_eql, ary1, ary2);
+    return rb_exec_recursive_paired(recursive_eql, ary1, ary2);
 }
 
@@ -2859,5 +2859,5 @@ recursive_cmp(VALUE ary1, VALUE ary2, in
     long i, len;
 
-    if (recur) return Qnil;
+    if (recur) return Qundef;	/* Subtle! */
     len = RARRAY_LEN(ary1);
     if (len > RARRAY_LEN(ary2)) {
@@ -2901,5 +2901,5 @@ rb_ary_cmp(VALUE ary1, VALUE ary2)
     ary2 = to_ary(ary2);
     if (ary1 == ary2) return INT2FIX(0);
-    v = rb_exec_recursive(recursive_cmp, ary1, ary2);
+    v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2);
     if (v != Qundef) return v;
     len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
Index: hash.c
===================================================================
--- hash.c	(revision 23373)
+++ hash.c	(working copy)
@@ -1489,5 +1489,5 @@ hash_equal(VALUE hash1, VALUE hash2, int
     data.tbl = RHASH(hash2)->ntbl;
     data.eql = eql;
-    return rb_exec_recursive(recursive_eql, hash1, (VALUE)&data);
+    return rb_exec_recursive_paired(recursive_eql, hash1, (VALUE)&data);
 }
 
Index: thread.c
===================================================================
--- thread.c	(revision 23373)
+++ thread.c	(working copy)
@@ -3311,5 +3311,5 @@ static ID recursive_key;
 
 static VALUE
-recursive_check(VALUE hash, VALUE obj)
+recursive_check(VALUE hash, VALUE obj, VALUE paired_obj)
 {
     if (NIL_P(hash) || TYPE(hash) != T_HASH) {
@@ -3317,10 +3317,23 @@ recursive_check(VALUE hash, VALUE obj)
     }
     else {
-	VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_this_func()));
+	VALUE sym = ID2SYM(rb_frame_this_func());
+	VALUE list = rb_hash_aref(hash, sym);
+	VALUE pair_list;
 
 	if (NIL_P(list) || TYPE(list) != T_HASH)
 	    return Qfalse;
-	if (NIL_P(rb_hash_lookup(list, obj)))
+	pair_list = rb_hash_lookup2(list, obj, Qundef);
+	if (pair_list == Qundef)
 	    return Qfalse;
+	if (paired_obj) {
+	    if (TYPE(pair_list) != T_HASH) {
+		if (pair_list != paired_obj)
+		    return Qfalse;
+	    }
+	    else {
+		if (NIL_P(rb_hash_lookup(pair_list, paired_obj)))
+		    return Qfalse;
+	    }
+	}
 	return Qtrue;
     }
@@ -3328,7 +3341,7 @@ recursive_check(VALUE hash, VALUE obj)
 
 static VALUE
-recursive_push(VALUE hash, VALUE obj)
+recursive_push(VALUE hash, VALUE obj, VALUE paired_obj)
 {
-    VALUE list, sym;
+    VALUE list, sym, pair_list;
 
     sym = ID2SYM(rb_frame_this_func());
@@ -3345,20 +3358,31 @@ recursive_push(VALUE hash, VALUE obj)
 	rb_hash_aset(hash, sym, list);
     }
-    rb_hash_aset(list, obj, Qtrue);
+    if (!paired_obj) {
+	rb_hash_aset(list, obj, Qtrue);
+    }
+    else if ((pair_list = rb_hash_lookup2(list, obj, Qundef)) == Qundef) {
+	rb_hash_aset(list, obj, paired_obj);
+    }
+    else {
+	if (TYPE(pair_list) != T_HASH){
+	    VALUE other_paired_obj = pair_list;
+	    pair_list = rb_hash_new();
+	    rb_hash_aset(pair_list, other_paired_obj, Qtrue);
+	    rb_hash_aset(list, obj, pair_list);
+	}
+	rb_hash_aset(pair_list, paired_obj, Qtrue);
+    }
     return hash;
 }
 
 static void
-recursive_pop(VALUE hash, VALUE obj)
+recursive_pop(VALUE hash, VALUE obj, VALUE paired_obj)
 {
-    VALUE list, sym;
+    VALUE list, sym, pair_list, symname, thrname;
 
     sym = ID2SYM(rb_frame_this_func());
     if (NIL_P(hash) || TYPE(hash) != T_HASH) {
-	VALUE symname;
-	VALUE thrname;
 	symname = rb_inspect(sym);
 	thrname = rb_inspect(rb_thread_current());
-
 	rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
 		 StringValuePtr(symname), StringValuePtr(thrname));
@@ -3366,19 +3390,34 @@ recursive_pop(VALUE hash, VALUE obj)
     list = rb_hash_aref(hash, sym);
     if (NIL_P(list) || TYPE(list) != T_HASH) {
-	VALUE symname = rb_inspect(sym);
-	VALUE thrname = rb_inspect(rb_thread_current());
+	symname = rb_inspect(sym);
+	thrname = rb_inspect(rb_thread_current());
 	rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
 		 StringValuePtr(symname), StringValuePtr(thrname));
     }
+    if (paired_obj) {
+	pair_list = rb_hash_lookup2(list, obj, Qundef);
+	if (pair_list == Qundef) {
+	    symname = rb_inspect(sym);
+	    thrname = rb_inspect(rb_thread_current());
+	    rb_raise(rb_eTypeError, "invalid inspect_tbl pair_list for %s in %s",
+		     StringValuePtr(symname), StringValuePtr(thrname));
+	}
+	if (TYPE(pair_list) == T_HASH) {
+	    rb_hash_delete(pair_list, obj);
+	    if (!RHASH_EMPTY_P(pair_list)) {
+		return; /* keep hash until is empty */
+	    }
+	}
+    }
     rb_hash_delete(list, obj);
 }
 
-VALUE
-rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
+static VALUE
+exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg, VALUE pairid)
 {
     volatile VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
     VALUE objid = rb_obj_id(obj);
 
-    if (recursive_check(hash, objid)) {
+    if (recursive_check(hash, objid, pairid)) {
 	return (*func) (obj, arg, Qtrue);
     }
@@ -3387,5 +3426,5 @@ rb_exec_recursive(VALUE (*func) (VALUE, 
 	int state;
 
-	hash = recursive_push(hash, objid);
+	hash = recursive_push(hash, objid, pairid);
 	PUSH_TAG();
 	if ((state = EXEC_TAG()) == 0) {
@@ -3393,5 +3432,5 @@ rb_exec_recursive(VALUE (*func) (VALUE, 
 	}
 	POP_TAG();
-	recursive_pop(hash, objid);
+	recursive_pop(hash, objid, pairid);
 	if (state)
 	    JUMP_TAG(state);
@@ -3400,4 +3439,16 @@ rb_exec_recursive(VALUE (*func) (VALUE, 
 }
 
+VALUE
+rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
+{
+    return exec_recursive(func, obj, arg, 0);
+}
+
+VALUE
+rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
+{
+    return exec_recursive(func, obj, arg, rb_obj_id(arg));
+}
+
 /* tracer */
 
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 23373)
+++ include/ruby/intern.h	(working copy)
@@ -341,4 +341,5 @@ void rb_thread_atfork(void);
 void rb_thread_atfork_before_exec(void);
 VALUE rb_exec_recursive(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
+VALUE rb_exec_recursive_paired(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
 /* file.c */
 VALUE rb_file_s_expand_path(int, VALUE *);


-- 
Nobu Nakada

In This Thread