summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-06-05 13:02:38 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-06-05 13:31:09 +0900
commit1624d77f3ee0a536a6ab37da014d85d16fcd1de2 (patch)
treed7c75edc564a30f3fcf4d3d3719d2bd11c7d63fe
parentb2fe7484e7e7c7741f33bfb02c2fc91f03763ab4 (diff)
error.c: avoid infinite recursion at inspecting the frozen object
-rw-r--r--error.c27
-rw-r--r--test/ruby/test_exception.rb15
2 files changed, 35 insertions, 7 deletions
diff --git a/error.c b/error.c
index 1e1af77d92..19265f65cb 100644
--- a/error.c
+++ b/error.c
@@ -2887,24 +2887,37 @@ rb_frozen_error_raise(VALUE frozen_obj, const char *fmt, ...)
rb_exc_raise(exc);
}
+static VALUE
+inspect_frozen_obj(VALUE obj, VALUE mesg, int recur)
+{
+ if (recur) {
+ rb_str_cat_cstr(mesg, " ...");
+ }
+ else {
+ rb_str_append(mesg, rb_inspect(obj));
+ }
+ return mesg;
+}
+
void
rb_error_frozen_object(VALUE frozen_obj)
{
VALUE debug_info;
const ID created_info = id_debug_created_info;
+ VALUE mesg = rb_sprintf("can't modify frozen %"PRIsVALUE": ",
+ CLASS_OF(frozen_obj));
+ VALUE exc = rb_exc_new_str(rb_eFrozenError, mesg);
+
+ rb_ivar_set(exc, id_recv, frozen_obj);
+ rb_exec_recursive(inspect_frozen_obj, frozen_obj, mesg);
if (!NIL_P(debug_info = rb_attr_get(frozen_obj, created_info))) {
VALUE path = rb_ary_entry(debug_info, 0);
VALUE line = rb_ary_entry(debug_info, 1);
- rb_frozen_error_raise(frozen_obj,
- "can't modify frozen %"PRIsVALUE": %"PRIsVALUE", created at %"PRIsVALUE":%"PRIsVALUE,
- CLASS_OF(frozen_obj), rb_inspect(frozen_obj), path, line);
- }
- else {
- rb_frozen_error_raise(frozen_obj, "can't modify frozen %"PRIsVALUE": %"PRIsVALUE,
- CLASS_OF(frozen_obj), rb_inspect(frozen_obj));
+ rb_str_catf(mesg, ", created at %"PRIsVALUE":%"PRIsVALUE, path, line);
}
+ rb_exc_raise(exc);
}
#undef rb_check_frozen
diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb
index 54e39a0f5f..c69d18b0c9 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -886,6 +886,21 @@ end.join
obj.instance_variable_set(:@test, true)
}
assert_include(e.message, obj.inspect)
+
+ klass = Class.new do
+ def init
+ @x = true
+ end
+ def inspect
+ init
+ super
+ end
+ end
+ obj = klass.new.freeze
+ e = assert_raise_with_message(FrozenError, /can't modify frozen #{obj.class}/) {
+ obj.init
+ }
+ assert_include(e.message, klass.inspect)
end
def test_name_error_new_default