Skip to content

Commit

Permalink
Fixed long stacktrace printing (#28453)
Browse files Browse the repository at this point in the history
(cherry picked from commit ba209d5)
  • Loading branch information
Liozou authored and ararslan committed Aug 7, 2018
1 parent 13d295c commit 26e2ee4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 12 deletions.
38 changes: 26 additions & 12 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -471,17 +471,18 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=()
end
end

# Contains file name and file number. Gets set when a backtrace
# or methodlist is shown. Used by the REPL to make it possible to open
# the location of a stackframe/method in the editor.
global LAST_SHOWN_LINE_INFOS = Tuple{String, Int}[]

function show_trace_entry(io, frame, n; prefix = "")
push!(LAST_SHOWN_LINE_INFOS, (string(frame.file), frame.line))
print(io, "\n", prefix)
show(io, frame, full_path=true)
n > 1 && print(io, " (repeats ", n, " times)")
end

# Contains file name and file number. Gets set when a backtrace
# or methodlist is shown. Used by the REPL to make it possible to open
# the location of a stackframe/method in the editor.
global LAST_SHOWN_LINE_INFOS = Tuple{String, Int}[]

# In case the line numbers in the source code have changed since the code was compiled,
# allow packages to set a callback function that corrects them.
# (Used by Revise and perhaps other packages.)
Expand All @@ -502,6 +503,10 @@ function show_reduced_backtrace(io::IO, t::Vector, with_prefix::Bool)
frame appears just before. =#

displayed_stackframes = []
repeated_cycle = Tuple{Int,Int,Int}[]
# First: line to introuce the "cycle repetition" message
# Second: length of the cycle
# Third: number of repetitions
frame_counter = 1
while frame_counter < length(t)
(last_frame, n) = t[frame_counter]
Expand All @@ -520,11 +525,10 @@ function show_reduced_backtrace(io::IO, t::Vector, with_prefix::Bool)
while i < length(t) && t[i] == t[j]
i+=1 ; j+=1
end
if j >= frame_counter
if j >= frame_counter-1
#= At least one cycle repeated =#
repetitions = div(i - frame_counter + 1, cycle_length)
print(io, "\n ... (the last ", cycle_length, " lines are repeated ",
repetitions, " more time", repetitions>1 ? "s)" : ")")
push!(repeated_cycle, (length(displayed_stackframes), cycle_length, repetitions))
frame_counter += cycle_length * repetitions - 1
break
end
Expand All @@ -537,13 +541,24 @@ function show_reduced_backtrace(io::IO, t::Vector, with_prefix::Bool)

try invokelatest(update_stackframes_callback[], displayed_stackframes) catch end

for (frame, n) in displayed_stackframes
push!(repeated_cycle, (0,0,0)) # repeated_cycle is never empty
frame_counter = 1
for i in 1:length(displayed_stackframes)
(frame, n) = displayed_stackframes[i]
if with_prefix
show_trace_entry(io, frame, n, prefix = string(" [", frame_counter-1, "] "))
push!(LAST_SHOWN_LINE_INFOS, (string(frame.file), frame.line))
show_trace_entry(io, frame, n, prefix = string(" [", frame_counter, "] "))
else
show_trace_entry(io, frame, n)
end
while repeated_cycle[1][1] == i # never empty because of the initial (0,0,0)
cycle_length = repeated_cycle[1][2]
repetitions = repeated_cycle[1][3]
popfirst!(repeated_cycle)
print(io, "\n ... (the last ", cycle_length, " lines are repeated ",
repetitions, " more time", repetitions>1 ? "s)" : ")")
frame_counter += cycle_length * repetitions
end
frame_counter += 1
end
end

Expand All @@ -568,7 +583,6 @@ function show_backtrace(io::IO, t::Vector)
for (last_frame, n) in filtered
frame_counter += 1
show_trace_entry(IOContext(io, :backtrace => true), last_frame, n, prefix = string(" [", frame_counter, "] "))
push!(LAST_SHOWN_LINE_INFOS, (string(last_frame.file), last_frame.line))
end
return
end
Expand Down
15 changes: 15 additions & 0 deletions test/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -521,3 +521,18 @@ end
end
end

# issue #28442
@testset "Long stacktrace printing" begin
f28442(c) = g28442(c + 1)
g28442(c) = c > 10000 ? (return backtrace()) : f28442(c+1)
bt = f28442(1)
io = IOBuffer()
Base.show_backtrace(io, bt)
output = split(String(take!(io)), '\n')
@test output[3][1:4] == " [1]"
@test occursin("g28442", output[3])
@test output[4][1:4] == " [2]"
@test occursin("f28442", output[4])
@test occursin("the last 2 lines are repeated 5000 more times", output[5])
@test output[6][1:8] == " [10003]"
end

0 comments on commit 26e2ee4

Please sign in to comment.