[Bug #19242] Prohibit circular causes to be loaded

This commit is contained in:
Nobuyoshi Nakada 2022-12-19 14:10:58 +09:00
parent 18ba89093a
commit 2e7e153a2a
Notes: git 2022-12-20 05:13:10 +00:00
4 changed files with 31 additions and 0 deletions

View File

@ -2959,6 +2959,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)
{
@ -2973,6 +2975,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);
}

4
eval.c
View File

@ -537,12 +537,16 @@ exc_setup_message(const rb_execution_context_t *ec, VALUE mesg, VALUE *cause)
}
if (!nocircular && !NIL_P(*cause) && !UNDEF_P(*cause) && *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;
}

View File

@ -290,6 +290,17 @@ show_cause(VALUE errinfo, VALUE str, VALUE opt, VALUE highlight, VALUE reverse,
}
}
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 opt, VALUE highlight, VALUE reverse)
{

View File

@ -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;