summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--compar.c9
-rw-r--r--include/ruby/intern.h1
-rw-r--r--test/ruby/test_comparable.rb7
-rw-r--r--thread.c12
5 files changed, 35 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 512428878d..0e05b9e058 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Oct 9 13:53:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compar.c (cmp_eq): fail if recursion. [ruby-core:57736] [Bug #9003]
+
+ * thread.c (rb_exec_recursive_paired_outer): new function which is
+ combinnation of paired and outer variants.
+
Wed Oct 9 09:18:14 2013 Koichi Sasada <ko1@atdot.net>
* include/ruby/debug.h,
diff --git a/compar.c b/compar.c
index eea76cb637..2f4db291a4 100644
--- a/compar.c
+++ b/compar.c
@@ -52,9 +52,16 @@ rb_invcmp(VALUE x, VALUE y)
}
static VALUE
+cmp_eq_recursive(VALUE arg1, VALUE arg2, int recursive)
+{
+ if (recursive) return Qfalse;
+ return rb_funcallv(arg1, cmp, 1, &arg2);
+}
+
+static VALUE
cmp_eq(VALUE *a)
{
- VALUE c = rb_funcall(a[0], cmp, 1, a[1]);
+ VALUE c = rb_exec_recursive_paired_outer(cmp_eq_recursive, a[0], a[1], a[1]);
if (NIL_P(c)) return Qfalse;
if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue;
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 757699bd91..fa0c075b83 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -448,6 +448,7 @@ 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,VALUE);
VALUE rb_exec_recursive_outer(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE);
+VALUE rb_exec_recursive_paired_outer(VALUE(*)(VALUE, VALUE, int),VALUE,VALUE,VALUE);
/* dir.c */
VALUE rb_dir_getwd(void);
/* file.c */
diff --git a/test/ruby/test_comparable.rb b/test/ruby/test_comparable.rb
index c686adeceb..747f1e29a7 100644
--- a/test/ruby/test_comparable.rb
+++ b/test/ruby/test_comparable.rb
@@ -76,4 +76,11 @@ class TestComparable < Test::Unit::TestCase
assert_nil(Time.new <=> "")
}
end
+
+ def test_no_cmp
+ bug9003 = '[ruby-core:57736] [Bug #9003]'
+ assert_nothing_raised(SystemStackError, bug9003) {
+ @o <=> @o.dup
+ }
+ end
end
diff --git a/thread.c b/thread.c
index 463f5d3b0e..4789dfa0e8 100644
--- a/thread.c
+++ b/thread.c
@@ -4954,6 +4954,18 @@ rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
}
/*
+ * If recursion is detected on the current method, obj and paired_obj,
+ * the outermost func will be called with (obj, arg, Qtrue). All inner
+ * func will be short-circuited using throw.
+ */
+
+VALUE
+rb_exec_recursive_paired_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
+{
+ return exec_recursive(func, obj, rb_obj_id(paired_obj), arg, 1);
+}
+
+/*
* call-seq:
* thread.backtrace -> array
*