mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
merge revision(s) 58471,58493: [Backport #13505]
load.c: backtrace of circular require * load.c (load_lock): print backtrace of circular require via `Warning.warn` [ruby-core:80850] [Bug #13505] Send the backtrace of the circular require warning as a single String to Warning.warn * load.c: send as a single string. * error.c: expose the string formatted by rb_warning as rb_warning_string(). * test/ruby/test_exception.rb: update tests. [ruby-core:80850] [Bug #13505] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@62435 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
4237809aa3
commit
ac84c2aee2
6 changed files with 69 additions and 16 deletions
16
error.c
16
error.c
|
@ -162,10 +162,16 @@ rb_warning_s_warn(VALUE mod, VALUE str)
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_warning_warn(VALUE mod, VALUE str)
|
||||
{
|
||||
return rb_funcallv(mod, id_warn, 1, &str);
|
||||
}
|
||||
|
||||
static void
|
||||
rb_write_warning_str(VALUE str)
|
||||
{
|
||||
rb_funcall(rb_mWarning, id_warn, 1, str);
|
||||
rb_warning_warn(rb_mWarning, str);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -254,6 +260,14 @@ rb_warning(const char *fmt, ...)
|
|||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_warning_string(const char *fmt, ...)
|
||||
{
|
||||
with_warning_string(mesg, 0, fmt) {
|
||||
}
|
||||
return mesg;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
rb_enc_warning(rb_encoding *enc, const char *fmt, ...)
|
||||
|
|
|
@ -1033,6 +1033,8 @@ VALUE rb_name_err_new(VALUE mesg, VALUE recv, VALUE method);
|
|||
rb_name_err_raise_str(rb_fstring_cstr(mesg), (recv), (name))
|
||||
NORETURN(void ruby_only_for_internal_use(const char *));
|
||||
#define ONLY_FOR_INTERNAL_USE(func) ruby_only_for_internal_use(func)
|
||||
VALUE rb_warning_warn(VALUE mod, VALUE str);
|
||||
VALUE rb_warning_string(const char *fmt, ...);
|
||||
|
||||
/* eval.c */
|
||||
VALUE rb_refinement_module_get_refined_class(VALUE module);
|
||||
|
@ -1641,7 +1643,7 @@ void rb_backtrace_print_as_bugreport(void);
|
|||
int rb_backtrace_p(VALUE obj);
|
||||
VALUE rb_backtrace_to_str_ary(VALUE obj);
|
||||
VALUE rb_backtrace_to_location_ary(VALUE obj);
|
||||
void rb_backtrace_print_to(VALUE output);
|
||||
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
|
||||
VALUE rb_vm_backtrace_object(void);
|
||||
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
|
|
7
load.c
7
load.c
|
@ -720,6 +720,8 @@ rb_f_load(int argc, VALUE *argv)
|
|||
return Qtrue;
|
||||
}
|
||||
|
||||
extern VALUE rb_mWarning;
|
||||
|
||||
static char *
|
||||
load_lock(const char *ftptr)
|
||||
{
|
||||
|
@ -742,8 +744,9 @@ load_lock(const char *ftptr)
|
|||
return (char *)"";
|
||||
}
|
||||
if (RTEST(ruby_verbose)) {
|
||||
rb_warning("loading in progress, circular require considered harmful - %s", ftptr);
|
||||
rb_backtrace_print_to(rb_stderr);
|
||||
VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
|
||||
rb_backtrace_each(rb_str_append, warning);
|
||||
rb_warning_warn(rb_mWarning, warning);
|
||||
}
|
||||
switch (rb_thread_shield_wait((VALUE)data)) {
|
||||
case Qfalse:
|
||||
|
|
|
@ -934,23 +934,23 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
|
|||
end
|
||||
end
|
||||
|
||||
def test_warning_warn
|
||||
def capture_warning_warn
|
||||
verbose = $VERBOSE
|
||||
warning = nil
|
||||
warning = []
|
||||
|
||||
::Warning.class_eval do
|
||||
alias_method :warn2, :warn
|
||||
remove_method :warn
|
||||
|
||||
define_method(:warn) do |str|
|
||||
warning = str
|
||||
warning << str
|
||||
end
|
||||
end
|
||||
|
||||
$VERBOSE = true
|
||||
a = @a
|
||||
yield
|
||||
|
||||
assert_match(/instance variable @a not initialized/, warning)
|
||||
return warning
|
||||
ensure
|
||||
$VERBOSE = verbose
|
||||
|
||||
|
@ -961,6 +961,11 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
|
|||
end
|
||||
end
|
||||
|
||||
def test_warning_warn
|
||||
warning = capture_warning_warn {@a}
|
||||
assert_match(/instance variable @a not initialized/, warning[0])
|
||||
end
|
||||
|
||||
def test_warning_warn_invalid_argument
|
||||
assert_raise(TypeError) do
|
||||
::Warning.warn nil
|
||||
|
@ -973,6 +978,27 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
|
|||
end
|
||||
end
|
||||
|
||||
def test_warning_warn_circular_require_backtrace
|
||||
warning = nil
|
||||
path = nil
|
||||
Tempfile.create(%w[circular .rb]) do |t|
|
||||
begin
|
||||
path = t.path
|
||||
basename = File.basename(path)
|
||||
t.puts "require '#{basename}'"
|
||||
t.close
|
||||
$LOAD_PATH.push(File.dirname(t))
|
||||
warning = capture_warning_warn {require basename}
|
||||
ensure
|
||||
$LOAD_PATH.pop
|
||||
$LOADED_FEATURES.delete(t)
|
||||
end
|
||||
end
|
||||
assert_equal(1, warning.size)
|
||||
assert_match(/circular require/, warning.first)
|
||||
assert_match(/^\tfrom #{Regexp.escape(path)}:1:/, warning.first)
|
||||
end
|
||||
|
||||
def test_undefined_backtrace
|
||||
assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
|
||||
begin;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#define RUBY_VERSION "2.4.4"
|
||||
#define RUBY_RELEASE_DATE "2018-02-16"
|
||||
#define RUBY_PATCHLEVEL 236
|
||||
#define RUBY_RELEASE_DATE "2018-02-17"
|
||||
#define RUBY_PATCHLEVEL 237
|
||||
|
||||
#define RUBY_RELEASE_YEAR 2018
|
||||
#define RUBY_RELEASE_MONTH 2
|
||||
#define RUBY_RELEASE_DAY 16
|
||||
#define RUBY_RELEASE_DAY 17
|
||||
|
||||
#include "ruby/version.h"
|
||||
|
||||
|
|
|
@ -778,10 +778,15 @@ rb_backtrace(void)
|
|||
vm_backtrace_print(stderr);
|
||||
}
|
||||
|
||||
struct print_to_arg {
|
||||
VALUE (*iter)(VALUE recv, VALUE str);
|
||||
VALUE output;
|
||||
};
|
||||
|
||||
static void
|
||||
oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
|
||||
{
|
||||
VALUE output = (VALUE)data;
|
||||
const struct print_to_arg *arg = data;
|
||||
VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
|
||||
|
||||
if (NIL_P(name)) {
|
||||
|
@ -790,16 +795,19 @@ oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
|
|||
else {
|
||||
rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
|
||||
}
|
||||
rb_io_write(output, str);
|
||||
(*arg->iter)(arg->output, str);
|
||||
}
|
||||
|
||||
void
|
||||
rb_backtrace_print_to(VALUE output)
|
||||
rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
|
||||
{
|
||||
struct oldbt_arg arg;
|
||||
struct print_to_arg parg;
|
||||
|
||||
parg.iter = iter;
|
||||
parg.output = output;
|
||||
arg.func = oldbt_print_to;
|
||||
arg.data = (void *)output;
|
||||
arg.data = &parg;
|
||||
backtrace_each(GET_THREAD(),
|
||||
oldbt_init,
|
||||
oldbt_iter_iseq,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue