You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index 2bfa45dd15..4a5dbb38a1 100644
--- a/Lib/asyncio/sslproto.py+++ b/Lib/asyncio/sslproto.py@@ -592,7 +592,7 @@ class SSLProtocol(protocols.Protocol):
# (b'', 1) is a special value in _process_write_backlog() to do
# the SSL handshake
self._write_backlog.append((b'', 1))
- self._loop.call_soon(self._process_write_backlog)+ self._process_write_backlog()
self._handshake_timeout_handle = \
self._loop.call_later(self._ssl_handshake_timeout,
self._check_handshake_timeout)
loop.start_tls() method is new in Python 3.7. If possible, I would prefer to not see it with a builtin race condition, since such race condition is really hard to debug :-( So I raise the priority to release blocker. Sorry again Ned!
Yury Selivanov told me that usually it's safer to add call_soon(), than to remove call_soon(). But adding many call_soon() can make asyncio SSL slower.
SSLProtocol doesn't seem to like call_soon(), it's only used at:
That's all. All other operations are done immediately.
_on_handshake_complete() contains a long comment:
# In case transport.write() was already called. Don't call# immediately _process_write_backlog(), but schedule it:# _on_handshake_complete() can be called indirectly from# _process_write_backlog(), and _process_write_backlog() is not# reentrant.self._loop.call_soon(self._process_write_backlog)
The fix is correct and the bug is now obvious: data_received() occur pretty much any time after connection_made() call; if call_soon() is used in connection_made(), data_received() may find the protocol in an incorrect state.
Activity
vstinner commentedon May 28, 2018
While debugging bpo-32458 (functional test on START TLS), I found a race condition in SSLProtocol of asyncio/sslproto.py.
Sometimes, _sslpipe.feed_ssldata() is called before _sslpipe.shutdown().
The first write is delayed by call_soon(), whereas the first read is a direct call to the SSL pipe.
vstinner commentedon May 28, 2018
Workaround:
vstinner commentedon May 28, 2018
loop.start_tls() method is new in Python 3.7. If possible, I would prefer to not see it with a builtin race condition, since such race condition is really hard to debug :-( So I raise the priority to release blocker. Sorry again Ned!
vstinner commentedon May 28, 2018
Yury Selivanov told me that usually it's safer to add call_soon(), than to remove call_soon(). But adding many call_soon() can make asyncio SSL slower.
SSLProtocol doesn't seem to like call_soon(), it's only used at:
That's all. All other operations are done immediately.
_on_handshake_complete() contains a long comment:
1st1 commentedon May 28, 2018
The fix is correct and the bug is now obvious: data_received() occur pretty much any time after connection_made() call; if call_soon() is used in connection_made(), data_received() may find the protocol in an incorrect state.
Kudos Victor for debugging this.
1st1 commentedon May 28, 2018
And I agree, this should make it to 3.7.0
vstinner commentedon May 28, 2018
New changeset be00a55 by Victor Stinner in branch 'master':
bpo-33674: asyncio: Fix SSLProtocol race (GH-7175)
be00a55
ned-deily commentedon May 29, 2018
New changeset 0dd8fd0 by Ned Deily (Miss Islington (bot)) in branch '3.7':
bpo-33674: asyncio: Fix SSLProtocol race (GH-7175) (bpo-7187)
0dd8fd0
1st1 commentedon May 29, 2018
New changeset 7593b8a by Yury Selivanov (Victor Stinner) in branch '3.6':
bpo-33674: asyncio: Fix SSLProtocol race (GH-7175) (GH-7188)
7593b8a
1st1 commentedon May 29, 2018
New changeset f295587 by Yury Selivanov in branch 'master':
bpo-33674: Pause the transport as early as possible (bpo-7192)
f295587
miss-islington commentedon May 29, 2018
New changeset eca0859 by Miss Islington (bot) in branch '3.7':
bpo-33674: Pause the transport as early as possible (GH-7192)
eca0859
vstinner commentedon May 29, 2018
I fixed the main issue, so I remove the "release blocker" priority.
vstinner commentedon May 29, 2018
Is it ok to always resume reading? Previously reading was only resumed if the transport was reading.
1st1 commentedon May 29, 2018
yes, the method is idempotent.
1st1 commentedon May 29, 2018
Closing this one. Please open new issues to track regressions.