Revision a311f4d8327a5051b11a6bcd1c44ed931d4ab261 authored by Jacob Quinn on 20 October 2022, 02:44:43 UTC, committed by GitHub on 20 October 2022, 02:44:43 UTC
As reported [here](https://discourse.julialang.org/t/test-failures-for-sockets-base-runtests-sockets/88898).

My guess on the original issue reported is that, for some reason, the host where the tests are run
is unable to listen on any ports, so we end up cycling through the entire UInt16 range (the test
starts at port 11011), but when we fail on port 65535, we do `addr.port + 1` and instead of wrapping
around as I believe this function intends to happen (as noted by the `addr.port == default_port` check
before we error), it gets promoted to `Int(65536)` which then throws an (unexpected) error in the `InetAddr`
constructor.

I'm not quite sure how to test this exactly though, because we'd need to simulate not being able
to listen on any ports? If anyone has any ideas, I'm all ears.
1 parent 0d52506
Raw File
backtrace.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license

import Base.StackTraces: lookup

# Test location information for inlined code (ref issues #1334 #12544)
module test_inline_bt
using Test
import ..lookup

function get_bt_frames(functionname, bt)
    for i = 1:length(bt)
        lkup = lookup(bt[i])
        lkup[end].func == functionname && return lkup
    end
    return StackTraces.StackFrame[]
end

# same-file inline
eval(Expr(:function, Expr(:call, :test_inline_1),
          Expr(:block, Expr(:line, 99, Symbol("backtrace.jl")),
                       Expr(:block, Expr(:line, 42),
                                    Expr(:meta, :push_loc, Symbol("backtrace.jl"), :inlfunc),
                                    Expr(:line, 37),
                                    Expr(:call, :throw, "foo"),
                                    Expr(:meta, :pop_loc),
                                    Expr(:line, 99)))))

@test functionloc(test_inline_1) == ("backtrace.jl", 99)
try
    test_inline_1()
    error("unexpected")
catch err
    lkup = get_bt_frames(:test_inline_1, catch_backtrace())
    @test length(lkup) == 2
    @test endswith(string(lkup[2].file), "backtrace.jl")
    @test lkup[2].line == 42
    # TODO: we don't support surface AST locations with inlined function names
    @test_broken lkup[1].func === :inlfunc
    @test endswith(string(lkup[1].file), "backtrace.jl")
    @test lkup[1].line == 37
end

# different-file inline
const absfilepath = Sys.iswindows() ? "C:\\foo\\bar\\baz.jl" : "/foo/bar/baz.jl"
eval(Expr(:function, Expr(:call, :test_inline_2),
          Expr(:block, Expr(:line, 81, Symbol("backtrace.jl")),
                       Expr(:block, Expr(:meta, :push_loc, Symbol(absfilepath)),
                                    Expr(:line, 111),
                                    Expr(:call, :throw, "foo"),
                                    Expr(:meta, :pop_loc),
                                    Expr(:line, 99)))))

@test functionloc(test_inline_2) == ("backtrace.jl", 81)
try
    test_inline_2()
    error("unexpected")
catch err
    lkup = get_bt_frames(:test_inline_2, catch_backtrace())
    @test length(lkup) == 2
    @test endswith(string(lkup[2].file), "backtrace.jl")
    @test lkup[2].line == 81
    @test string(lkup[1].file) == absfilepath
    @test lkup[1].line == 111
end

end # module

#issue 12977: line numbers for kwarg methods.
linenum = @__LINE__; f12977(; args...) = ()
loc = functionloc(f12977)
@test endswith(loc[1], "backtrace.jl")
@test loc[2] == linenum

@noinline function test_throw_commoning(x)
    if x==1; throw(AssertionError()); end
    if x==2; throw(AssertionError()); end
end

let
    local b1, b2
    try
        test_throw_commoning(1)
    catch
        b1 = stacktrace(catch_backtrace())
    end
    try
        test_throw_commoning(2)
    catch
        b2 = stacktrace(catch_backtrace())
    end
    i1 = findfirst(frame -> frame.func === :test_throw_commoning, b1)
    i2 = findfirst(frame -> frame.func === :test_throw_commoning, b2)
    @test i1 > 0 && i2 > 0
    @test b1[i1].line != b2[i2].line
end

module BackTraceTesting
using Test
import ..lookup

@inline bt2() = backtrace()
@inline bt1() = bt2()
bt() = bt1()

lkup = map(lookup, bt())
hasbt = hasbt2 = false
for sfs in lkup
    for sf in sfs
        if sf.func === :bt
            global hasbt = true
        end
        if sf.func === :bt2
            global hasbt2 = true
        end
    end
end
@test hasbt
@test hasbt2

function btmacro()
    ret = @timed backtrace()
    ret[1]
end
lkup = map(lookup, btmacro())
hasme = hasbtmacro = false
for sfs in lkup
    for sf in sfs
        if sf.func === Symbol("macro expansion")
            global hasme = true
        end
        if sf.func === :btmacro
            global hasbtmacro = true
        end
    end
end
@test hasme
@test hasbtmacro

end

# Interpreter backtraces
bt = eval(quote
    try
        error()
    catch
        catch_backtrace()
    end
end)
lkup = map(lookup, bt)
hastoplevel = false
for sfs in lkup
    for sf in sfs
        if sf.linfo isa Core.CodeInfo
            global hastoplevel = true
        end
    end
end
@test hastoplevel

# issue #23971
let
    for i = 1:1
        global bt23971 = backtrace()
    end
end
let st = stacktrace(bt23971)
    @test StackTraces.is_top_level_frame(st[1])
    @test string(st[1].file) == @__FILE__
    @test !occursin("missing", string(st[2].file))
end

# issue #27959
let bt, found = false
    @testset begin
        bt = backtrace()
    end
    for frame in map(lookup, bt)
        if frame[1].line == @__LINE__() - 3 && frame[1].file === Symbol(@__FILE__)
            found = true; break
        end
    end
    @test found
end

# issue 28618
let bt, found = false
    @debug ""
    bt = backtrace()
    for frame in map(lookup, bt)
        if frame[1].line == @__LINE__() - 2 && frame[1].file === Symbol(@__FILE__)
            found = true; break
        end
    end
    @test found
end

# Syntax error locations appear in backtraces
let trace = try
        include_string(@__MODULE__,
            """

            )

            """, "a_filename")
    catch
        stacktrace(catch_backtrace())
    end
    @test trace[1].func === Symbol("top-level scope")
    @test trace[1].file === :a_filename
    @test trace[1].line == 2
end
let trace = try
        include_string(@__MODULE__,
            """

            incomplete_syntax(

            """, "a_filename")
    catch
        stacktrace(catch_backtrace())
    end
    @test trace[1].func === Symbol("top-level scope")
    @test trace[1].file === :a_filename
    @test trace[1].line == 2
end

# issue #45171
linenum = @__LINE__; function f45171(;kwarg = true)
    1
    error()
end
let trace = try
        f45171()
    catch
        stacktrace(catch_backtrace())
    end
    @test trace[3].line == linenum
end

# issue #29695 (see also test for #28442)
let code = """
    f29695(c) = g29695(c)
    g29695(c) = c >= 1000 ? (return backtrace()) : f29695(c + 1)
    bt = f29695(1)
    meth_names = [ip.code.def.name for ip in bt
                  if ip isa Base.InterpreterIP && ip.code isa Core.MethodInstance]
    num_fs = sum(meth_names .== :f29695)
    num_gs = sum(meth_names .== :g29695)
    print(num_fs, ' ', num_gs)
    """

    @test read(`$(Base.julia_cmd()) --startup-file=no --compile=min -e $code`, String) == "1000 1000"
end

# Test that modules make it into InterpreterIP for top-level code
let code = """
    module A
    foo() = error("Expected")
    try
        foo()
    catch
        global bt = catch_backtrace()
    end
    end

    foreach(println, A.bt)
    """

    bt_str = read(`$(Base.julia_cmd()) --startup-file=no --compile=min -e $code`, String)
    @test occursin(r"InterpreterIP in MethodInstance for .*A\.foo", bt_str)
    @test occursin("InterpreterIP in top-level CodeInfo for Main.A", bt_str)
end

"""
    _reformat_sp(bt_data...) -> sp::Vector{Ptr{Cvoid}}

Convert the output `bt_data` of `jl_backtrace_from_here` with `returnsp` flag set to a
vector of valid stack pointers `sp`; i.e., `sp` is a subset of `bt_data[3]`.

See also `Base._reformat_bt`.
"""
function _reformat_sp(
    bt_raw::Array{Ptr{Cvoid},1},
    bt2::Array{Any,1},
    sp_raw::Array{Ptr{Cvoid},1},
)
    bt = Base._reformat_bt(bt_raw, bt2)
    sp = empty!(similar(sp_raw))
    i = j = 0
    while true
        # Advance `i` such that `bt[i] isa Ptr{Cvoid}` (native pointer).
        local ip
        while true
            if i == lastindex(bt)
                return sp
            end
            i += 1
            x = bt[i]
            if x isa Ptr{Cvoid}
                ip = x
                break
            end
        end
        # Advance `j` such that `bt_raw[j] == bt[i]` to find a valid stack pointer.
        while true
            if j == lastindex(bt_raw)
                return sp
            end
            j += 1
            if bt_raw[j] == ip
                push!(sp, sp_raw[j])
                break
            end
        end
    end
end

"""
    withframeaddress(f)

Call function `f` with an address `ptr::Ptr{Cvoid}` of an independent frame
immediately outer to `f`.
"""
withframeaddress
@eval @noinline function withframeaddress(f)
    sp = Core.Intrinsics.llvmcall(
        ($"""
        declare i8* @llvm.frameaddress(i32)
        define private i$(Sys.WORD_SIZE) @frameaddr() {
            %1 = call i8* @llvm.frameaddress(i32 0)
            %2 = ptrtoint i8* %1 to i$(Sys.WORD_SIZE)
            ret i$(Sys.WORD_SIZE) %2
        }""", "frameaddr"),
        UInt,
        Tuple{},
    )
    @noinline f(Ptr{Cvoid}(sp))
end

function sandwiched_backtrace()
    local ptr1, ptr2, bt
    withframeaddress() do p1
        ptr1 = p1
        bt = ccall(:jl_backtrace_from_here, Ref{Base.SimpleVector}, (Cint, Cint), true, 0)
        withframeaddress() do p2
            ptr2 = p2
        end
    end
    return ptr1, ptr2, bt
end

@testset "stack pointers" begin
    ptr1, ptr2, bt_data = sandwiched_backtrace()
    sp = _reformat_sp(bt_data...)
    @test ptr2 < sp[2]
    @test sp[1] < ptr1
    @test all(diff(Int128.(UInt.(sp))) .> 0)
end
back to top