Skip to content

Commit

Permalink
Restore StackOverflow error message for repeated frames
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.
  • Loading branch information
NHDaly authored and JeffBezanson committed Mar 5, 2021
1 parent bf0364b commit 71f28ad
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 @@ -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
Expand Down Expand Up @@ -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

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

Please sign in to comment.