diff --git a/base/task.jl b/base/task.jl index 8c9516fb397665..0d37e1fe9eae28 100644 --- a/base/task.jl +++ b/base/task.jl @@ -79,7 +79,12 @@ end function show_task_exception(io::IO, t::Task; indent = true) stack = catch_stack(t) b = IOBuffer() - show_exception_stack(IOContext(b, io), stack) + if isempty(stack) + # exception stack buffer not available; probably a serialized task + showerror(IOContext(b, io), t.result) + else + show_exception_stack(IOContext(b, io), stack) + end str = String(take!(b)) if indent str = replace(str, "\n" => "\n ") diff --git a/stdlib/Distributed/src/clusterserialize.jl b/stdlib/Distributed/src/clusterserialize.jl index 3fde2bb4c2bd68..e37987c5bf8751 100644 --- a/stdlib/Distributed/src/clusterserialize.jl +++ b/stdlib/Distributed/src/clusterserialize.jl @@ -102,19 +102,6 @@ function serialize(s::ClusterSerializer, t::Core.TypeName) nothing end -function serialize(s::ClusterSerializer, t::Task) - serialize_cycle(s, t) && return - if istaskstarted(t) && !istaskdone(t) - error("cannot serialize a running Task") - end - writetag(s.io, TASK_TAG) - serialize(s, t.code) - serialize(s, t.storage) - serialize(s, t._state) - serialize(s, t.result) - serialize(s, t._isexception) -end - function serialize(s::ClusterSerializer, g::GlobalRef) # Record if required and then invoke the default GlobalRef serializer. sym = g.name @@ -244,17 +231,6 @@ function deserialize(s::ClusterSerializer, t::Type{<:CapturedException}) return CapturedException(capex, bt) end -function deserialize(s::ClusterSerializer, ::Type{Task}) - t = Task(nothing) - deserialize_cycle(s, t) - t.code = deserialize(s) - t.storage = deserialize(s) - t._state = deserialize(s)::UInt8 - t.result = deserialize(s) - t._isexception = deserialize(s) - t -end - """ clear!(syms, pids=workers(); mod=Main) diff --git a/stdlib/Distributed/test/distributed_exec.jl b/stdlib/Distributed/test/distributed_exec.jl index 656792e2d73373..7f804c51082ac2 100644 --- a/stdlib/Distributed/test/distributed_exec.jl +++ b/stdlib/Distributed/test/distributed_exec.jl @@ -1697,7 +1697,7 @@ let e = @test_throws RemoteException pmap(1) do _ es = sprint(showerror, e.value) @test contains(es, ":\nTaskFailedException\nStacktrace:\n") @test contains(es, "\n\n nested task error:") - @test_broken contains(es, "\n\n nested task error: 42\n") + @test contains(es, "\n\n nested task error: 42\n") end # issue #27429, propagate relative `include` path to workers diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index 1c1cf00d0f426a..80b1946e795646 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -444,11 +444,19 @@ function serialize(s::AbstractSerializer, t::Task) if istaskstarted(t) && !istaskdone(t) error("cannot serialize a running Task") end - state = [t.code, t.storage, t.state, t.result, t._isexception] writetag(s.io, TASK_TAG) - for fld in state - serialize(s, fld) + serialize(s, t.code) + serialize(s, t.storage) + serialize(s, t.state) + if t._isexception && (stk = Base.catch_stack(t); !isempty(stk)) + # the exception stack field is hidden inside the task, so if there + # is any information there make a CapturedException from it instead. + # TODO: Handle full exception chain, not just the first one. + serialize(s, CapturedException(stk[1][1], stk[1][2])) + else + serialize(s, t.result) end + serialize(s, t._isexception) end function serialize(s::AbstractSerializer, g::GlobalRef)