ruby-changes:63443
From: Benoit <ko1@a...>
Date: Mon, 26 Oct 2020 16:47:52 +0900 (JST)
Subject: [ruby-changes:63443] cffdacb15a (master): Ignore <internal: entries from core library methods for Kernel#warn(message, uplevel: n)
https://git.ruby-lang.org/ruby.git/commit/?id=cffdacb15a From cffdacb15a363321e1c1879aa7d94924acafd1cf Mon Sep 17 00:00:00 2001 From: Benoit Daloze <eregontp@g...> Date: Sun, 11 Oct 2020 13:36:25 +0200 Subject: Ignore <internal: entries from core library methods for Kernel#warn(message, uplevel: n) * Fixes [Bug #17259] diff --git a/error.c b/error.c index d58075f..2e02fbf 100644 --- a/error.c +++ b/error.c @@ -504,7 +504,8 @@ warning_write(int argc, VALUE *argv, VALUE buf) https://github.com/ruby/ruby/blob/trunk/error.c#L504 return buf; } -VALUE rb_ec_backtrace_location_ary(rb_execution_context_t *ec, long lev, long n); +VALUE rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal); + static VALUE rb_warn_m(rb_execution_context_t *ec, VALUE exc, VALUE msgs, VALUE uplevel, VALUE category) { @@ -519,7 +520,7 @@ rb_warn_m(rb_execution_context_t *ec, VALUE exc, VALUE msgs, VALUE uplevel, VALU https://github.com/ruby/ruby/blob/trunk/error.c#L520 if (lev < 0) { rb_raise(rb_eArgError, "negative level (%ld)", lev); } - location = rb_ec_backtrace_location_ary(ec, lev + 1, 1); + location = rb_ec_backtrace_location_ary(ec, lev + 1, 1, TRUE); if (!NIL_P(location)) { location = rb_ary_entry(location, 0); } diff --git a/eval_intern.h b/eval_intern.h index 48e9c89..83d7056 100644 --- a/eval_intern.h +++ b/eval_intern.h @@ -299,7 +299,7 @@ VALUE rb_vm_cbase(void); https://github.com/ruby/ruby/blob/trunk/eval_intern.h#L299 /* vm_backtrace.c */ VALUE rb_ec_backtrace_object(const rb_execution_context_t *ec); VALUE rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n); -VALUE rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n); +VALUE rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal); #ifndef CharNext /* defined as CharNext[AW] on Windows. */ # ifdef HAVE_MBLEN diff --git a/spec/ruby/core/kernel/fixtures/warn_core_method.rb b/spec/ruby/core/kernel/fixtures/warn_core_method.rb new file mode 100644 index 0000000..f5dee6b --- /dev/null +++ b/spec/ruby/core/kernel/fixtures/warn_core_method.rb @@ -0,0 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/kernel/fixtures/warn_core_method.rb#L1 +raise 'should be run without RubyGems' if defined?(Gem) + +def deprecated(n=1) + # puts nil, caller(0), nil + warn "use X instead", uplevel: n +end + +1.times do # to test with a non-empty stack above the reported locations + deprecated + tap(&:deprecated) + tap { deprecated(2) } + # eval sources with a <internal: file are also ignored + eval "tap(&:deprecated)", nil, "<internal:should-be-skipped-by-warn-uplevel>" +end diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb index fcba164..5953a47 100644 --- a/spec/ruby/core/kernel/warn_spec.rb +++ b/spec/ruby/core/kernel/warn_spec.rb @@ -114,6 +114,22 @@ describe "Kernel#warn" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/kernel/warn_spec.rb#L114 end end + guard -> { Kernel.instance_method(:tap).source_location } do + it "skips <internal: core library methods defined in Ruby" do + file, line = Kernel.instance_method(:tap).source_location + file.should.start_with?('<internal:') + + file = fixture(__FILE__ , "warn_core_method.rb") + n = 9 + ruby_exe(file, options: "--disable-gems", args: "2>&1").lines.should == [ + "#{file}:#{n+0}: warning: use X instead\n", + "#{file}:#{n+1}: warning: use X instead\n", + "#{file}:#{n+2}: warning: use X instead\n", + "#{file}:#{n+4}: warning: use X instead\n", + ] + end + end + ruby_version_is "3.0" do it "accepts :category keyword with a symbol" do -> { diff --git a/vm_backtrace.c b/vm_backtrace.c index 0826ab0..f2cc212 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -601,6 +601,15 @@ struct bt_iter_arg { https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L601 rb_backtrace_location_t *init_loc; }; +static bool +is_internal_location(const rb_control_frame_t *cfp) +{ + static const char prefix[] = "<internal:"; + const size_t prefix_len = sizeof(prefix) - 1; + VALUE file = rb_iseq_path(cfp->iseq); + return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0; +} + static void bt_init(void *ptr, size_t size) { @@ -627,6 +636,27 @@ bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp) https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L636 } static void +bt_iter_iseq_skip_internal(void *ptr, const rb_control_frame_t *cfp) +{ + struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr; + rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++-1]; + + if (!is_internal_location(cfp)) { + loc->type = LOCATION_TYPE_ISEQ; + loc->body.iseq.iseq = cfp->iseq; + loc->body.iseq.lineno.pc = cfp->pc; + arg->prev_loc = loc; + } else if (arg->prev_cfp) { + loc->type = LOCATION_TYPE_ISEQ; + loc->body.iseq.iseq = arg->prev_cfp->iseq; + loc->body.iseq.lineno.pc = arg->prev_cfp->pc; + arg->prev_loc = loc; + } else { + rb_bug("No non-internal backtrace entry before an <internal: backtrace entry"); + } +} + +static void bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid) { struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr; @@ -656,8 +686,18 @@ bt_iter_skip(void *ptr, const rb_control_frame_t *cfp) https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L686 } } +static void +bt_iter_skip_skip_internal(void *ptr, const rb_control_frame_t *cfp) +{ + if (cfp->iseq && cfp->pc) { + if (!is_internal_location(cfp)) { + ((struct bt_iter_arg *) ptr)->prev_cfp = cfp; + } + } +} + static VALUE -rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long lev, long n, int* level_too_large) +rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long lev, long n, int* level_too_large, bool skip_internal) { struct bt_iter_arg arg; int too_large; @@ -667,9 +707,9 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long lev, long https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L707 lev, n, bt_init, - bt_iter_iseq, + skip_internal ? bt_iter_iseq_skip_internal : bt_iter_iseq, bt_iter_cfunc, - bt_iter_skip, + skip_internal ? bt_iter_skip_skip_internal : bt_iter_skip, &arg); if (level_too_large) *level_too_large = too_large; @@ -680,7 +720,7 @@ rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long lev, long https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L720 MJIT_FUNC_EXPORTED VALUE rb_ec_backtrace_object(const rb_execution_context_t *ec) { - return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL); + return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE); } static VALUE @@ -802,13 +842,13 @@ backtrace_load_data(VALUE self, VALUE str) https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L842 VALUE rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n) { - return backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL)); + return backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE)); } VALUE -rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n) +rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal) { - return backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL)); + return backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal)); } /* make old style backtrace directly */ @@ -1031,7 +1071,7 @@ ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *arg https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1071 return rb_ary_new(); } - btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large); + btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE); if (too_large) { return Qnil; @@ -1355,7 +1395,7 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data) https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1395 dbg_context.ec = ec; dbg_context.cfp = dbg_context.ec->cfp; - dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES); + dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, FALSE); dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace); dbg_context.contexts = collect_caller_bindings(ec); -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/