Skip to content

Commit

Permalink
Restore StackOverflow error message for repeated frames (#39930)
Browse files Browse the repository at this point in the history
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 <nhdaly@gmail.com>
(cherry picked from commit 3276c11)
  • Loading branch information
JeffBezanson authored and KristofferC committed Mar 14, 2021
1 parent 7a4413b commit f20b49a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 7 deletions.
13 changes: 6 additions & 7 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
27 changes: 27 additions & 0 deletions test/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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()

0 comments on commit f20b49a

Please sign in to comment.