Skip to content

Commit

Permalink
[Serialization] support AbstractLock and GenericCondition (JuliaLang#…
Browse files Browse the repository at this point in the history
…43325)

Locks should be unlocked when serialized, and GenericCondition should
drop their waiters.

Otherwise, we may try to serialize a running Task (the user should
normally be holding the lock around the data they are intending to
serialize), which will fail and error.
  • Loading branch information
vtjnash authored and LilithHafner committed Mar 8, 2022
1 parent ac80528 commit 9b87ee9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
18 changes: 18 additions & 0 deletions base/deepcopy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,21 @@ function deepcopy_internal(x::Union{Dict,IdDict}, stackdict::IdDict)
end
dest
end

function deepcopy_internal(x::AbstractLock, stackdict::IdDict)
if haskey(stackdict, x)
return stackdict[x]
end
y = typeof(x)()
stackdict[x] = y
return y
end

function deepcopy_internal(x::GenericCondition, stackdict::IdDict)
if haskey(stackdict, x)
return stackdict[x]
end
y = typeof(x)(deepcopy_internal(x.lock))
stackdict[x] = y
return y
end
26 changes: 26 additions & 0 deletions stdlib/Serialization/src/Serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1528,4 +1528,30 @@ function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
end

function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
# assert_havelock(lock)
serialize_cycle_header(s, lock)
nothing
end

function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
lock = T()
deserialize_cycle(s, lock)
return lock
end

function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
serialize_cycle_header(s, cond) && return
serialize(s, cond.lock)
nothing
end

function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
lock = deserialize(s)
cond = T(lock)
deserialize_cycle(s, cond)
return cond
end


end
18 changes: 18 additions & 0 deletions stdlib/Serialization/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -624,3 +624,21 @@ end
@test_broken f(1) == 2
end
end

let c1 = Threads.Condition()
c2 = Threads.Condition(c1.lock)
lock(c2)
t = @task nothing
Base._wait2(c1, t)
c3, c4 = deserialize(IOBuffer(sprint(serialize, [c1, c2])))::Vector{Threads.Condition}
@test c3.lock === c4.lock
@test islocked(c1)
@test !islocked(c3)
@test !isempty(c1.waitq)
@test isempty(c2.waitq)
@test isempty(c3.waitq)
@test isempty(c4.waitq)
notify(c1)
unlock(c2)
wait(t)
end

0 comments on commit 9b87ee9

Please sign in to comment.