From c05d019cb4778ac04088df69541aab0762d849f8 Mon Sep 17 00:00:00 2001 From: nagachika Date: Wed, 9 Oct 2013 16:36:05 +0000 Subject: [PATCH] merge revision(s) 43208: [Backport #9003] * 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@43230 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 7 +++++++ compar.c | 9 ++++++++- include/ruby/intern.h | 1 + test/ruby/test_comparable.rb | 7 +++++++ thread.c | 12 ++++++++++++ version.h | 2 +- 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8d28b719f..cb9e93121c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Thu Oct 10 01:14:37 2013 Nobuyoshi Nakada + + * 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. + Thu Oct 10 01:07:37 2013 Nobuyoshi Nakada * lib/tempfile.rb (Tempfile#unlink): finalizer is no longer needed diff --git a/compar.c b/compar.c index c89c752daf..fc04946e3f 100644 --- a/compar.c +++ b/compar.c @@ -51,10 +51,17 @@ rb_invcmp(VALUE x, VALUE y) } } +static VALUE +cmp_eq_recursive(VALUE arg1, VALUE arg2, int recursive) +{ + if (recursive) return Qfalse; + return rb_funcall(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 c447b37223..b1dff0b7b9 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -426,6 +426,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 b2ec68a623..d859982fe5 100644 --- a/thread.c +++ b/thread.c @@ -4877,6 +4877,18 @@ rb_exec_recursive_outer(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg) return exec_recursive(func, obj, 0, arg, 1); } +/* + * 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: * thr.backtrace -> array diff --git a/version.h b/version.h index f4b1ecfc7f..8ac1ebe8ad 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ #define RUBY_VERSION "2.0.0" #define RUBY_RELEASE_DATE "2013-10-10" -#define RUBY_PATCHLEVEL 333 +#define RUBY_PATCHLEVEL 334 #define RUBY_RELEASE_YEAR 2013 #define RUBY_RELEASE_MONTH 10