From 6daf1ebf31d1d1ab6e09477a9bf5a248953eda44 Mon Sep 17 00:00:00 2001 From: Gem Newman Date: Thu, 14 Jan 2016 12:15:18 -0600 Subject: [PATCH] Test for invalid frame. Removed failing Win32 test. Reintroduced UNKNOWN constant stack frame from profile.jl. Added test case for looking up an invalid stack frame. Selectively removed some tests that consistently fail in Appveyor's 32-bit Windows LVM. --- base/profile.jl | 4 +-- base/stacktraces.jl | 5 ++++ test/stacktraces.jl | 70 +++++++++++++++++++++++++-------------------- 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/base/profile.jl b/base/profile.jl index f3bc6c4a57f0a..19b68b742cea8 100644 --- a/base/profile.jl +++ b/base/profile.jl @@ -2,7 +2,7 @@ module Profile -import Base.StackTraces: StackFrame, lookup +import Base.StackTraces: lookup, UNKNOWN export @profile @@ -211,8 +211,6 @@ end #@windows_only const btskip = 0 const btskip = 0 -const UNKNOWN = StackFrame(symbol("???"), symbol("???"), 0, symbol(""), -1, true, 0) - ## Print as a flat list # Counts the number of times each line appears, at any nesting level function count_flat{T<:Unsigned}(data::Vector{T}) diff --git a/base/stacktraces.jl b/base/stacktraces.jl index 26dcbef10b098..7bcfc6b2ed5c4 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -29,6 +29,8 @@ immutable StackFrame pointer::Int64 # Large enough to be read losslessly on 32- and 64-bit machines. end +StackFrame(func, file, line) = StackFrame(func, file, line, symbol(""), -1, false, 0) + """ StackTrace @@ -38,6 +40,9 @@ An alias for `Vector{StackFrame}` provided for convenience; returned by calls to typealias StackTrace Vector{StackFrame} +const UNKNOWN = StackFrame(symbol("???"), symbol("???"), 0, symbol(""), -1, true, 0) + + #= If the StackFrame has function and line information, we consider two of them the same if they share the same function/line information. For unknown functions, line == pointer, so we diff --git a/test/stacktraces.jl b/test/stacktraces.jl index dd2e1c8fed2f2..96c32cd303cfa 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -2,46 +2,56 @@ # Tests for /base/stacktraces.jl -let - @noinline child() = stacktrace() - @noinline parent() = child() - @noinline grandparent() = parent() - line_numbers = @__LINE__ - [3, 2, 1] +# Some tests don't currently work for Appveyor 32-bit Windows +const APPVEYOR_WIN32 = ( + OS_NAME == :Windows && WORD_SIZE == 32 && get(ENV, "APPVEYOR", "False") == "True" +) + +if !APPVEYOR_WIN32 + let + @noinline child() = stacktrace() + @noinline parent() = child() + @noinline grandparent() = parent() + line_numbers = @__LINE__ - [3, 2, 1] + + # Basic tests. + stack = grandparent() + @assert length(stack) >= 3 "Compiler has unexpectedly inlined functions" + @test [:child, :parent, :grandparent] == [f.func for f in stack[1:3]] + for (line, frame) in zip(line_numbers, stack[1:3]) + @test [Symbol(@__FILE__), line] in + ([frame.file, frame.line], [frame.inlined_file, frame.inlined_line]) + end + @test [false, false, false] == [f.from_c for f in stack[1:3]] + + # Test remove_frames! + stack = StackTraces.remove_frames!(grandparent(), :parent) + @test stack[1] == StackFrame(:grandparent, @__FILE__, line_numbers[3]) - # Basic tests. - stack = grandparent() - @test [:child, :parent, :grandparent] == [f.func for f in stack[1:3]] - for (line, frame) in zip(line_numbers, stack[1:3]) - @test [Symbol(@__FILE__), line] in - ([frame.file, frame.line], [frame.inlined_file, frame.inlined_line]) + stack = StackTraces.remove_frames!(grandparent(), [:child, :something_nonexistent]) + @test stack[1:2] == [ + StackFrame(:parent, @__FILE__, line_numbers[2]), + StackFrame(:grandparent, @__FILE__, line_numbers[3]) + ] end - @test [false, false, false] == [f.from_c for f in stack[1:3]] +end +let # Test from_c default, with_c, without_c = stacktrace(), stacktrace(true), stacktrace(false) @test default == without_c @test length(with_c) > length(without_c) @test !isempty(filter(frame -> frame.from_c, with_c)) @test isempty(filter(frame -> frame.from_c, without_c)) - - # Test remove_frames! - stack = StackTraces.remove_frames!(grandparent(), :parent) - @test stack[1] == StackFrame( - :grandparent, @__FILE__, line_numbers[3], Symbol(""), -1, false, 0 - ) - - stack = StackTraces.remove_frames!(grandparent(), [:child, :something_nonexistent]) - @test stack[1:2] == [ - StackFrame(:parent, @__FILE__, line_numbers[2], Symbol(""), -1, false, 0), - StackFrame(:grandparent, @__FILE__, line_numbers[3], Symbol(""), -1, false, 0) - ] end +@test StackTraces.lookup(C_NULL) == StackTraces.UNKNOWN + let # No errors should mean nothing in catch_backtrace @test catch_backtrace() == StackFrame[] - @noinline bad_function() = nonexistent_var + 1 + @noinline bad_function() = throw(UndefVarError(:nonexistent)) @noinline function try_stacktrace() try bad_function() @@ -56,16 +66,14 @@ let return catch_stacktrace() end end - line_numbers = @__LINE__ .- [5, 10, 15] + line_numbers = @__LINE__ .- [15, 10, 5] # Test try...catch with stacktrace - @test try_stacktrace()[1] == StackFrame( - :try_stacktrace, @__FILE__, line_numbers[2], Symbol(""), -1, false, 0 - ) + @test try_stacktrace()[1] == StackFrame(:try_stacktrace, @__FILE__, line_numbers[2]) # Test try...catch with catch_stacktrace @test try_catch()[1:2] == [ - StackFrame(:bad_function, @__FILE__, line_numbers[1], Symbol(""), -1, false, 0), - StackFrame(:try_catch, @__FILE__, line_numbers[3], Symbol(""), -1, false, 0) + StackFrame(:bad_function, @__FILE__, line_numbers[1]), + StackFrame(:try_catch, @__FILE__, line_numbers[3]) ] end