diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb index e61c1ad231..a340463c98 100644 --- a/lib/bundled_gems.rb +++ b/lib/bundled_gems.rb @@ -143,18 +143,8 @@ module Gem::BUNDLED_GEMS # Additionally, we need to skip Bootsnap and Zeitwerk if present, these # gems decorate Kernel#require, so they are not really the ones issuing # the require call users should be warned about. Those are upwards. - frames_to_skip = 2 - location = nil - Thread.each_caller_location do |cl| - if frames_to_skip >= 1 - frames_to_skip -= 1 - next - end - - if cl.base_label != "require" - location = cl.path - break - end + location = Thread.each_caller_location(2) do |cl| + break cl.path unless cl.base_label == "require" end if location && File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR) diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb index dbece06cd8..29c271789b 100644 --- a/spec/ruby/core/thread/each_caller_location_spec.rb +++ b/spec/ruby/core/thread/each_caller_location_spec.rb @@ -40,10 +40,10 @@ describe "Thread.each_caller_location" do }.should raise_error(LocalJumpError, "no block given") end - it "doesn't accept positional and keyword arguments" do + it "doesn't accept keyword arguments" do -> { Thread.each_caller_location(12, foo: 10) {} - }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") + }.should raise_error(ArgumentError); end end end diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb index 2691aa1332..c7364484b4 100644 --- a/spec/ruby/optional/capi/spec_helper.rb +++ b/spec/ruby/optional/capi/spec_helper.rb @@ -33,12 +33,6 @@ def compile_extension(name) ruby_header = "#{rubyhdrdir}/ruby.h" abi_header = "#{rubyhdrdir}/ruby/internal/abi.h" - if RbConfig::CONFIG["ENABLE_SHARED"] == "yes" - # below is defined since 2.1, except for mswin, and maybe other platforms - libdirname = RbConfig::CONFIG.fetch 'libdirname', 'libdir' - libruby = "#{RbConfig::CONFIG[libdirname]}/#{RbConfig::CONFIG['LIBRUBY']}" - end - begin mtime = File.mtime(lib) rescue Errno::ENOENT @@ -49,7 +43,6 @@ def compile_extension(name) when mtime <= File.mtime("#{spec_ext_dir}/#{ext}.c") when mtime <= File.mtime(ruby_header) when (mtime <= File.mtime(abi_header) rescue nil) - when libruby && mtime <= File.mtime(libruby) else return lib # up-to-date end diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index cfc65faacb..fca7b62030 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -155,6 +155,10 @@ class TestBacktrace < Test::Unit::TestCase end def test_each_backtrace_location + assert_nil(Thread.each_caller_location {}) + + assert_raise(LocalJumpError) {Thread.each_caller_location} + i = 0 cl = caller_locations(1, 1)[0]; ecl = Thread.each_caller_location{|x| i+=1; break x if i == 1} assert_equal(cl.to_s, ecl.to_s) @@ -181,6 +185,10 @@ class TestBacktrace < Test::Unit::TestCase assert_raise(StopIteration) { ecl.next } + + ary = [] + cl = caller_locations(1, 2); Thread.each_caller_location(1, 2) {|x| ary << x} + assert_equal(cl.map(&:to_s), ary.map(&:to_s)) end def test_caller_locations_first_label diff --git a/vm_backtrace.c b/vm_backtrace.c index 3fe816930d..22b28368d7 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -1170,17 +1170,17 @@ rb_make_backtrace(void) return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES); } -static VALUE -ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str) +static long +ec_backtrace_range(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, long *len_ptr) { - VALUE level, vn; + VALUE level, vn, opts; long lev, n; - VALUE btval; - VALUE r; - int too_large; - rb_scan_args(argc, argv, "02", &level, &vn); + rb_scan_args(argc, argv, "02:", &level, &vn, &opts); + if (!NIL_P(opts)) { + rb_get_kwargs(opts, (ID []){0}, 0, 0, NULL); + } if (argc == 2 && NIL_P(vn)) argc--; switch (argc) { @@ -1201,7 +1201,7 @@ ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *arg n = ALL_BACKTRACE_LINES; break; case Qnil: - return Qnil; + return -1; default: lev = beg + lev_plus; n = len; @@ -1225,6 +1225,20 @@ ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *arg break; } + *len_ptr = n; + return lev; +} + +static VALUE +ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str) +{ + long lev, n; + VALUE btval, r; + int too_large; + + lev = ec_backtrace_range(ec, argc, argv, lev_default, lev_plus, &n); + if (lev < 0) return Qnil; + if (n == 0) { return rb_ary_new(); } @@ -1354,15 +1368,19 @@ rb_f_caller_locations(int argc, VALUE *argv, VALUE _) /* * call-seq: - * Thread.each_caller_location{ |loc| ... } -> nil + * Thread.each_caller_location(...) { |loc| ... } -> nil * * Yields each frame of the current execution stack as a * backtrace location object. */ static VALUE -each_caller_location(VALUE unused) +each_caller_location(int argc, VALUE *argv, VALUE _) { - rb_ec_partial_backtrace_object(GET_EC(), 2, ALL_BACKTRACE_LINES, NULL, FALSE, TRUE); + rb_execution_context_t *ec = GET_EC(); + long n, lev = ec_backtrace_range(ec, argc, argv, 1, 1, &n); + if (lev >= 0 && n != 0) { + rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, TRUE); + } return Qnil; } @@ -1442,7 +1460,7 @@ Init_vm_backtrace(void) rb_define_global_function("caller", rb_f_caller, -1); rb_define_global_function("caller_locations", rb_f_caller_locations, -1); - rb_define_singleton_method(rb_cThread, "each_caller_location", each_caller_location, 0); + rb_define_singleton_method(rb_cThread, "each_caller_location", each_caller_location, -1); } /* debugger API */