Skip to content

Commit

Permalink
Fix potential race condition during disconnection (#2719)
Browse files Browse the repository at this point in the history
When the disconnect() function is called twice in parallel it is possible that
one thread deletes the self._sock reference, while the other thread will
attempt to call .close() on it, leading to an AttributeError.

This situation can routinely be encountered by closing the connection in a
PubSubWorkerThread error handler in a blocking thread (ie. with
sleep_time==None), and then calling .close() on the PubSub object.
The main thread will then run into the disconnect() function, and the listener
thread is woken up by the closure and will race into the disconnect()
function, too.

This can be fixed easily by copying the object reference before doing the
None-check, similar to what we do in the redis.client.close() function.
  • Loading branch information
Anthchirp authored May 1, 2023
1 parent 1ca223a commit ac15d52
Showing 1 changed file with 6 additions and 4 deletions.
10 changes: 6 additions & 4 deletions redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,20 +779,22 @@ def on_connect(self):
def disconnect(self, *args):
"Disconnects from the Redis server"
self._parser.on_disconnect()
if self._sock is None:

conn_sock = self._sock
self._sock = None
if conn_sock is None:
return

if os.getpid() == self.pid:
try:
self._sock.shutdown(socket.SHUT_RDWR)
conn_sock.shutdown(socket.SHUT_RDWR)
except OSError:
pass

try:
self._sock.close()
conn_sock.close()
except OSError:
pass
self._sock = None

def _send_ping(self):
"""Send PING, expect PONG in return"""
Expand Down

0 comments on commit ac15d52

Please sign in to comment.