From f20b49afccac0998d91b1ff990cf6772b1d1638f 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 (cherry picked from commit 3276c11b7e6ebf0c3867022765c8b233c0cbefe5) --- 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 f340df9738299..0ef1234e4d616 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -573,17 +573,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 @@ -782,8 +782,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 6dcf1e279be62..4a04aaed15fc4 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -676,6 +676,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] @@ -761,3 +762,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()