[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]