Skip to content

Commit

Permalink
Allow access to exception stack of a failed task
Browse files Browse the repository at this point in the history
  • Loading branch information
c42f committed Sep 20, 2018
1 parent 02d0270 commit 41a6eac
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 13 deletions.
18 changes: 11 additions & 7 deletions base/error.jl
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,20 @@ function catch_backtrace()
end

"""
catch_stack(; [inclue_bt=true])
catch_stack(task=current_task(); [inclue_bt=true])
Get the stack of exceptions currently being handled. For nested catch blocks
there may be more than one current exception in which case the most recent
exception is last in the stack. The stack is returned as a Vector of
`(exception,backtrace)` pairs, or a Vector of exceptions only if `include_bt`
is false.
there may be more than one current exception in which case the most recently
thrown exception is last in the stack. The stack is returned as a Vector of
`(exception,backtrace)` pairs, or a Vector of exceptions if `include_bt` is
false.
Explicitly passing `task` will return the current exception stack on an
arbitrary task. This is useful for inspecting tasks which have failed due to
uncaught exceptions.
"""
function catch_stack(; include_bt=true)
raw = ccall(:jl_get_exc_stack, Any, (Cint,Cint), include_bt, typemax(Cint))
function catch_stack(task=current_task(); include_bt=true)
raw = ccall(:jl_get_exc_stack, Any, (Any,Cint,Cint), task, include_bt, typemax(Cint))
formatted = Any[]
stride = include_bt ? 3 : 1
for i = reverse(1:stride:length(raw))
Expand Down
13 changes: 8 additions & 5 deletions src/stackwalk.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,20 @@ JL_DLLEXPORT void jl_get_backtrace(jl_array_t **btout, jl_array_t **bt2out)
decode_backtrace(bt_data, bt_size, btout, bt2out);
}

// Return data from the exception stack as an array of Any, starting with the
// top of the stack and returning up to `max_entries`. If requested by setting
// the `include_bt` flag, backtrace data in bt,bt2 format is interleaved.
JL_DLLEXPORT jl_value_t *jl_get_exc_stack(int include_bt, int max_entries)
// Return data from the exception stack for `task` as an array of Any, starting
// with the top of the stack and returning up to `max_entries`. If requested by
// setting the `include_bt` flag, backtrace data in bt,bt2 format is
// interleaved.
JL_DLLEXPORT jl_value_t *jl_get_exc_stack(jl_value_t* task, int include_bt, int max_entries)
{
jl_array_t *stack = NULL;
jl_array_t *bt = NULL;
jl_array_t *bt2 = NULL;
JL_GC_PUSH3(&stack, &bt, &bt2);
stack = jl_alloc_array_1d(jl_array_any_type, 0);
jl_exc_stack_t *s = jl_get_ptls_states()->current_task->exc_stack;
if (!jl_typeis(task, jl_task_type))
jl_error("Cannot get exception stack from a non-Task type");
jl_exc_stack_t *s = ((jl_task_t*)task)->exc_stack;
if (!s)
return (jl_value_t*)stack;
size_t itr = s->top;
Expand Down
12 changes: 11 additions & 1 deletion test/exceptions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ end
@test length(catch_stack()) == 0
end

@testset "Exception stacks and Task switching" begin
@testset "Exception stacks and Tasks" begin
# See #12485
try
error("A")
Expand Down Expand Up @@ -174,6 +174,16 @@ end
@test bt == catch_backtrace()
end
@test length(catch_stack()) == 0
# Exception stacks on other tasks
t = @task try
error("A")
catch
error("B")
end
yield(t)
@test t.state == :failed
@test t.result == ErrorException("B")
@test catch_stack(t, include_bt=false) == [ErrorException("A"), ErrorException("B")]
end

@testset "rethrow" begin
Expand Down

0 comments on commit 41a6eac

Please sign in to comment.