From 80dd6c304238b21cd373fdd734b613ef064d6bd2 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 11 Mar 2021 13:20:02 -0500 Subject: [PATCH] Restore StackOverflow error message for repeated frames (#39930) Fixes backtrace printing to display the number of times a frame is repeated, if there is a frame that's duplicated several times. ```julia julia> function foo() foo() end foo (generic function with 1 method) julia> foo() ERROR: StackOverflowError: Stacktrace: [1] foo() (repeats 79984 times) @ Main ./REPL[16]:1 ``` Fixes #37587. Co-authored-by: Nathan Daly --- base/errorshow.jl | 13 ++++++------- test/errorshow.jl | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 34f29f2a4aeaf..2baf5d2471315 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -570,17 +570,17 @@ stacktrace_linebreaks()::Bool = tryparse(Bool, get(ENV, "JULIA_STACKTRACE_LINEBREAKS", "false")) === true function show_full_backtrace(io::IO, trace::Vector; print_linebreaks::Bool) - n = length(trace) - ndigits_max = ndigits(n) + num_frames = length(trace) + ndigits_max = ndigits(num_frames) modulecolordict = copy(STACKTRACE_FIXEDCOLORS) modulecolorcycler = Iterators.Stateful(Iterators.cycle(STACKTRACE_MODULECOLORS)) println(io, "\nStacktrace:") - for (i, frame) in enumerate(trace) - print_stackframe(io, i, frame, 1, ndigits_max, modulecolordict, modulecolorcycler) - if i < n + for (i, (frame, n)) in enumerate(trace) + print_stackframe(io, i, frame, n, ndigits_max, modulecolordict, modulecolorcycler) + if i < num_frames println(io) print_linebreaks && println(io) end @@ -779,8 +779,7 @@ function show_backtrace(io::IO, t::Vector) try invokelatest(update_stackframes_callback[], filtered) catch end # process_backtrace returns a Vector{Tuple{Frame, Int}} - frames = map(x->first(x)::StackFrame, filtered) - show_full_backtrace(io, frames; print_linebreaks = stacktrace_linebreaks()) + show_full_backtrace(io, filtered; print_linebreaks = stacktrace_linebreaks()) return end diff --git a/test/errorshow.jl b/test/errorshow.jl index 30c7d61bdadde..736e68dee1ef0 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -678,6 +678,7 @@ end @test getline(outputc) == getline(output0) + 2 end + # issue #30633 @test_throws ArgumentError("invalid index: \"foo\" of type String") [1]["foo"] @test_throws ArgumentError("invalid index: nothing of type Nothing") [1][nothing] @@ -763,3 +764,29 @@ let err = nothing @test !occursin("2d", err_str) end end + +# issue #37587 +# TODO: enable on more platforms +if Sys.isapple() || (Sys.islinux() && Sys.ARCH === :x86_64) + single_repeater() = single_repeater() + pair_repeater_a() = pair_repeater_b() + pair_repeater_b() = pair_repeater_a() + + @testset "repeated stack frames" begin + let bt = try single_repeater() + catch + catch_backtrace() + end + bt_str = sprint(Base.show_backtrace, bt) + @test occursin(r"repeats \d+ times", bt_str) + end + + let bt = try pair_repeater_a() + catch + catch_backtrace() + end + bt_str = sprint(Base.show_backtrace, bt) + @test occursin(r"the last 2 lines are repeated \d+ more times", bt_str) + end + end +end # Sys.isapple()