fix a deadlock when Python garbage collects LDAPBackend objects

we shouldn't call signal.disconnect in __del__ because it can lead to
deadlocks in Django signal dispatch code

The Signal.connect, Signal.disconnect, and Signal._live_receivers
methods all share a threading.Lock():

22a60f8d0b/django/dispatch/dispatcher.py (L49)

It's possible for this to lead to a deadlock:

1.  Have code that calls Signal._live_receivers and enter the critical
    path inside the shared threading.Lock()
2.  Python garbage collection occurs and finds one or more LDAPBackend
    objects with no more references
3.  This __del__ is called, which calls Signal.disconnect
4.  Code in Signal._disconnect attempts to obtain the (already held)
    threading.Lock
5.  Python hangs forever while attempting to garbage collect
This commit is contained in:
Ryan Petrello 2019-01-18 11:21:47 -05:00
parent 5f01c3f5a8
commit e45e4b3cda
No known key found for this signature in database
GPG Key ID: F2AA5F2122351777

View File

@ -69,9 +69,6 @@ class LDAPBackend(BaseLDAPBackend):
super(LDAPBackend, self).__init__(*args, **kwargs)
setting_changed.connect(self._on_setting_changed, dispatch_uid=self._dispatch_uid)
def __del__(self):
setting_changed.disconnect(dispatch_uid=self._dispatch_uid)
def _on_setting_changed(self, sender, **kwargs):
# If any AUTH_LDAP_* setting changes, force settings to be reloaded for
# this backend instance.