aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2020-05-15 01:22:56 +0900
committerGitHub <noreply@github.com>2020-05-15 01:22:56 +0900
commit39365b46e250162f278cb36aa148bc2a92b1b84a (patch)
tree4eb62c6d4143dd0bd095a8f6c0cd5b89f7a59a7f
parent531e4a35f4c9c772aae331281cad324c6806c603 (diff)
downloadruby-39365b46e250162f278cb36aa148bc2a92b1b84a.tar.gz
Merge pull request #3047 from mame/suppress-backtrace
Add `--suppress-backtrace=num` option to limit the backtrace length
-rw-r--r--doc/fiber.rdoc6
-rw-r--r--error.c1
-rw-r--r--eval_error.c32
-rw-r--r--internal/error.h1
-rw-r--r--ruby.c7
5 files changed, 35 insertions, 12 deletions
diff --git a/doc/fiber.rdoc b/doc/fiber.rdoc
index d3c19a0d14..4a489edd3a 100644
--- a/doc/fiber.rdoc
+++ b/doc/fiber.rdoc
@@ -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
diff --git a/error.c b/error.c
index 4912869e43..31ffc32723 100644
--- a/error.c
+++ b/error.c
@@ -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;
diff --git a/eval_error.c b/eval_error.c
index 89e27afe56..e8a7243b96 100644
--- a/eval_error.c
+++ b/eval_error.c
@@ -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;
- }
}
}
}
diff --git a/internal/error.h b/internal/error.h
index 06eb0c4b3e..ff60d0075d 100644
--- a/internal/error.h
+++ b/internal/error.h
@@ -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;
diff --git a/ruby.c b/ruby.c
index 901556fb86..ba515bf277 100644
--- a/ruby.c
+++ b/ruby.c
@@ -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);