From da4d6d413516f42176fd86512863db5c265e029a Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 7 Dec 2021 17:04:17 +0400 Subject: [PATCH] fix potential deadlock due to inconsistent locking order --- stream.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/stream.go b/stream.go index 8213860..1a27949 100644 --- a/stream.go +++ b/stream.go @@ -376,21 +376,14 @@ func (s *Stream) cleanup() { // processFlags is used to update the state of the stream // based on set flags, if any. Lock must be held func (s *Stream) processFlags(flags uint16) { - // Close the stream without holding the state lock - closeStream := false - defer func() { - if closeStream { - s.cleanup() - } - }() + var establishStream, closeStream, notify bool s.stateLock.Lock() - defer s.stateLock.Unlock() if flags&flagACK == flagACK { if s.state == streamSYNSent { s.state = streamEstablished } - s.session.establishStream(s.id) + establishStream = true } if flags&flagFIN == flagFIN { if s.readState == halfOpen { @@ -400,6 +393,7 @@ func (s *Stream) processFlags(flags uint16) { closeStream = true s.state = streamFinished } + notify = true s.notifyWaiting() } } @@ -412,8 +406,20 @@ func (s *Stream) processFlags(flags uint16) { } s.state = streamFinished closeStream = true + notify = true s.notifyWaiting() } + s.stateLock.Unlock() + + if establishStream { + s.session.establishStream(s.id) + } + if notify { + s.notifyWaiting() + } + if closeStream { + s.cleanup() + } } // notifyWaiting notifies all the waiting channels