1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Merge pull request #3047 from mame/suppress-backtrace

Add `--suppress-backtrace=num` option to limit the backtrace length
This commit is contained in:
Yusuke Endoh 2020-05-15 01:22:56 +09:00 committed by GitHub
parent 531e4a35f4
commit 39365b46e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2020-05-15 01:23:19 +09:00
Merged-By: mame <mame@ruby-lang.org>
5 changed files with 35 additions and 12 deletions

View file

@ -88,13 +88,13 @@ context switching points.
Fiber.new(blocking: false) do
puts Fiber.current.blocking? # false
# May invoke `Thread.scheduler&.wait_readable`.
# May invoke `Thread.current.scheduler&.wait_readable`.
io.read(...)
# May invoke `Thread.scheduler&.wait_writable`.
# May invoke `Thread.current.scheduler&.wait_writable`.
io.write(...)
# Will invoke `Thread.scheduler&.wait_sleep`.
# Will invoke `Thread.current.scheduler&.wait_sleep`.
sleep(n)
end.resume

View file

@ -64,6 +64,7 @@ VALUE rb_iseqw_local_variables(VALUE iseqval);
VALUE rb_iseqw_new(const rb_iseq_t *);
int rb_str_end_with_asciichar(VALUE str, int c);
long rb_backtrace_length_limit = -1;
VALUE rb_eEAGAIN;
VALUE rb_eEWOULDBLOCK;
VALUE rb_eEINPROGRESS;

View file

@ -233,29 +233,43 @@ print_backtrace(const VALUE eclass, const VALUE errat, const VALUE str, int reve
if (!NIL_P(errat)) {
long i;
long len = RARRAY_LEN(errat);
int skip = eclass == rb_eSysStackError;
const int threshold = 1000000000;
int width = (len <= 1) ? INT_MIN : ((int)log10((double)(len > threshold ?
((len - 1) / threshold) :
len - 1)) +
(len < threshold ? 0 : 9) + 1);
#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
#define TRACE_HEAD 8
#define TRACE_TAIL 5
long skip_start = -1, skip_len = 0;
// skip for stackoverflow
if (eclass == rb_eSysStackError) {
long trace_head = 9;
long trace_tail = 4;
long trace_max = trace_head + trace_tail + 5;
if (len > trace_max) {
skip_start = trace_head;
skip_len = len - trace_max + 5;
}
}
// skip for explicit limit
if (rb_backtrace_length_limit >= 0 && len > rb_backtrace_length_limit + 1) {
skip_start = rb_backtrace_length_limit + 1;
skip_len = len - rb_backtrace_length_limit;
}
for (i = 1; i < len; i++) {
if (i == skip_start) {
write_warn_str(str, rb_sprintf("\t ... %ld levels...\n", skip_len));
i += skip_len;
if (i >= len) break;
}
VALUE line = RARRAY_AREF(errat, reverse ? len - i : i);
if (RB_TYPE_P(line, T_STRING)) {
VALUE bt = rb_str_new_cstr("\t");
if (reverse) rb_str_catf(bt, "%*ld: ", width, len - i);
write_warn_str(str, rb_str_catf(bt, "from %"PRIsVALUE"\n", line));
}
if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
write_warn_str(str, rb_sprintf("\t ... %ld levels...\n",
len - TRACE_HEAD - TRACE_TAIL));
i = len - TRACE_TAIL;
}
}
}
}

View file

@ -46,6 +46,7 @@ typedef enum {
RB_WARN_CATEGORY_EXPERIMENTAL,
} rb_warning_category_t;
extern long rb_backtrace_length_limit;
extern VALUE rb_eEAGAIN;
extern VALUE rb_eEWOULDBLOCK;
extern VALUE rb_eEINPROGRESS;

7
ruby.c
View file

@ -309,6 +309,7 @@ usage(const char *name, int help, int highlight, int columns)
M("--verbose", "", "turn on verbose mode and disable script from stdin"),
M("--version", "", "print the version number, then exit"),
M("--help", "", "show this message, -h for short message"),
M("--backtrace-limit=num", "", "limit the maximum length of backtrace"),
};
static const struct message dumps[] = {
M("insns", "", "instruction sequences"),
@ -1423,6 +1424,12 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
opt->dump |= DUMP_BIT(help);
goto switch_end;
}
else if (is_option_with_arg("backtrace-limit", Qfalse, Qfalse)) {
char *e;
long n = strtol(s, &e, 10);
if (errno == ERANGE || n < 0 || *e) rb_raise(rb_eRuntimeError, "wrong limit for backtrace length");
rb_backtrace_length_limit = n;
}
else {
rb_raise(rb_eRuntimeError,
"invalid option --%s (-h will show valid options)", s);