summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2023-03-25 11:04:33 +0900
committernagachika <nagachika@ruby-lang.org>2023-03-25 11:04:33 +0900
commit810ae06c06312908fc1a7284773d8a9101ee145b (patch)
tree5b9dd70da37a85caac30c80e71b5dbc4efd08665
parent8c99882dad0b6fedbd656889829a3780366bd8b6 (diff)
downloadruby-810ae06c06312908fc1a7284773d8a9101ee145b.tar.gz
merge revision(s) 2e7e153a2af1456515d43b6381e38534b069b1c2: [Backport #19242]
[Bug #19242] Prohibit circular causes to be loaded --- error.c | 4 ++++ eval.c | 4 ++++ eval_error.c | 11 +++++++++++ test/ruby/test_exception.rb | 12 ++++++++++++ 4 files changed, 31 insertions(+)
-rw-r--r--error.c4
-rw-r--r--eval.c4
-rw-r--r--eval_error.c11
-rw-r--r--test/ruby/test_exception.rb12
-rw-r--r--version.h2
5 files changed, 32 insertions, 1 deletions
diff --git a/error.c b/error.c
index a870d0200b..65ad20a27b 100644
--- a/error.c
+++ b/error.c
@@ -2846,6 +2846,8 @@ ivar_copy_i(st_data_t key, st_data_t val, st_data_t exc)
return ST_CONTINUE;
}
+void rb_exc_check_circular_cause(VALUE exc);
+
static VALUE
exception_loader(VALUE exc, VALUE obj)
{
@@ -2860,6 +2862,8 @@ exception_loader(VALUE exc, VALUE obj)
rb_ivar_foreach(obj, ivar_copy_i, exc);
+ rb_exc_check_circular_cause(exc);
+
if (rb_attr_get(exc, id_bt) == rb_attr_get(exc, id_bt_locations)) {
rb_ivar_set(exc, id_bt_locations, Qnil);
}
diff --git a/eval.c b/eval.c
index 0de3105ac7..97484b0b2a 100644
--- a/eval.c
+++ b/eval.c
@@ -528,12 +528,16 @@ exc_setup_message(const rb_execution_context_t *ec, VALUE mesg, VALUE *cause)
}
if (!nocircular && !NIL_P(*cause) && *cause != Qundef && *cause != mesg) {
+#if 0 /* maybe critical for some cases */
+ rb_exc_check_circular_cause(*cause);
+#else
VALUE c = *cause;
while (!NIL_P(c = rb_attr_get(c, id_cause))) {
if (c == mesg) {
rb_raise(rb_eArgError, "circular causes");
}
}
+#endif
}
return mesg;
}
diff --git a/eval_error.c b/eval_error.c
index 9b453eede0..1baa4484a0 100644
--- a/eval_error.c
+++ b/eval_error.c
@@ -311,6 +311,17 @@ show_cause(VALUE errinfo, VALUE str, VALUE highlight, VALUE reverse, long backtr
}
void
+rb_exc_check_circular_cause(VALUE exc)
+{
+ VALUE cause = exc, shown_causes = 0;
+ do {
+ if (shown_cause_p(cause, &shown_causes)) {
+ rb_raise(rb_eArgError, "circular causes");
+ }
+ } while (!NIL_P(cause = rb_attr_get(cause, id_cause)));
+}
+
+void
rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlight, VALUE reverse)
{
volatile VALUE eclass;
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index f99bb230a3..ffca877f1e 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -1412,6 +1412,18 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
end;
end
+ def test_marshal_circular_cause
+ begin
+ raise RuntimeError, "err", [], cause: Exception.new
+ rescue => e
+ end
+ dump = Marshal.dump(e).sub(/o:\x0EException\x08;.0;.0;.0/, "@\x05")
+ assert_raise_with_message(ArgumentError, /circular cause/, ->{dump.inspect}) do
+ e = Marshal.load(dump)
+ assert_same(e, e.cause)
+ end
+ end
+
def test_super_in_method_missing
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
diff --git a/version.h b/version.h
index 5688813a20..6965efef46 100644
--- a/version.h
+++ b/version.h
@@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 4
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 212
+#define RUBY_PATCHLEVEL 213
#define RUBY_RELEASE_YEAR 2023
#define RUBY_RELEASE_MONTH 3