Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stackoverflow in type inference caused by handling a StackOverflow exception #49507

Closed
NHDaly opened this issue Apr 26, 2023 · 2 comments · Fixed by #49508
Closed

stackoverflow in type inference caused by handling a StackOverflow exception #49507

NHDaly opened this issue Apr 26, 2023 · 2 comments · Fixed by #49508

Comments

@NHDaly
Copy link
Member

NHDaly commented Apr 26, 2023

We saw this rather comical exception pop up in our production cloud deployment:

Internal error: stack overflow in type inference of close(Base.Channel{Bool}, StackOverflowError).

As described above, this comes from a place in our code that performs a generic operation like this:

function http_handler()
    result = Channel()
    do_stuff()
    return_result_or_report_error(result)
end

# ... much later, after much processing on the server  ...
function do_stuff_inner_function(result_channel)
    try
        put!(result_channel, user_func())
    catch e
        close(result_channel, e)
    end
end

In this case, the try block happened to execute when the stack was very nearly full, so the user_func() threw a StackOverflowException. This is perfectly fine -- the code is set up to handle exceptions, and so the result should now contain the StackOverflowException, which, once everything unwinds, could be reported at the top level http handler.

However, what actually happens is the close(::Channel, ::StackOverflowExeption) triggers type inference, which causes another stack overflow! 😅


Looking at that function, i'm pretty sure that it the exception argument should be marked @nospecialize, since the generated code is going to be identical no matter what: c.excp is type Union{Exception, Nothing}, and all the other functions it calls with excp are already @nospecialize:

julia/base/channels.jl

Lines 186 to 198 in 2d14390

function close(c::Channel, excp::Exception=closed_exception())
lock(c)
try
c.excp = excp
@atomic :release c.state = :closed
notify_error(c.cond_take, excp)
notify_error(c.cond_wait, excp)
notify_error(c.cond_put, excp)
finally
unlock(c)
end
nothing
end

@NHDaly
Copy link
Member Author

NHDaly commented Apr 26, 2023

To add some more detail: looking at our stacktrace, we can see that the dynamic dispatch was directly on the call to close().

Internal error: stack overflow in type inference of close(Base.Channel{Bool}, StackOverflowError).
This might be caused by recursion over very long tuples or argument lists.
Internal error: encountered unexpected error during compilation of close:
StackOverflowError()
emit_expr at /build/source/src/codegen.cpp:4630
emit_call at /build/source/src/codegen.cpp:3812
...
ijl_apply_generic at /build/source/src/gf.c:2549
_set_exception at src/<internal-file>.jl:290

NHDaly added a commit that referenced this issue Apr 26, 2023
Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.
@NHDaly
Copy link
Member Author

NHDaly commented Apr 26, 2023

BTW here's a simple reproducer:

julia> ch = let result = Channel()

       foo() = try
           foo()
       catch e;
           close(result, e)
       end

       foo()

       result
       end
Internal error: stack overflow in type inference of close(Base.Channel{Any}, StackOverflowError).
This might be caused by recursion over very long tuples or argument lists.
Internal error: encountered unexpected error during compilation of close:
StackOverflowError()
Internal error: stack overflow in type inference of close(Base.Channel{Any}, StackOverflowError).
This might be caused by recursion over very long tuples or argument lists.
Internal error: encountered unexpected error during compilation of close:
StackOverflowError()
_ZL9emit_exprR12jl_codectx_tP11_jl_value_tl at /Users/nathandaly/builds/julia-1.8/usr/lib/libjulia-codegen.1.8.dylib (unknown line)
_ZL9emit_exprR12jl_codectx_tP11_jl_value_tl at /Users/nathandaly/builds/julia-1.8/usr/lib/libjulia-codegen.1.8.dylib (unknown line)

NHDaly added a commit that referenced this issue Apr 26, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
KristofferC pushed a commit that referenced this issue May 8, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.

(cherry picked from commit a152d11)
NHDaly added a commit that referenced this issue May 15, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit that referenced this issue May 15, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit that referenced this issue May 15, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit that referenced this issue May 15, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit that referenced this issue May 15, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit that referenced this issue May 15, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit that referenced this issue May 17, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
kpamnany pushed a commit to RelationalAI/julia that referenced this issue Jun 6, 2023
…9508)

* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes JuliaLang#49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
kpamnany pushed a commit to RelationalAI/julia that referenced this issue Jun 6, 2023
…9508)

* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes JuliaLang#49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
NHDaly added a commit to RelationalAI/julia that referenced this issue Jun 7, 2023
…9508) (#13)

* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes JuliaLang#49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.
kpamnany pushed a commit that referenced this issue Jun 21, 2023
* Nospecialize close(c::Channel, excp::Exception) on excp.

Fixes #49507.

Avoids dynamic dispatch when closing a Channel with an Exception, and
should avoid a call into the runtime for julia compilation when
attempting to report an exception.

* Add test for this case.

(cherry picked from commit a152d11)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant