From e45e4b3cda3198f902b1e19974bc70d48636be81 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Fri, 18 Jan 2019 11:21:47 -0500 Subject: [PATCH] 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(): https://github.com/django/django/blob/22a60f8d0b331bf06c066ccba4eea5bb5e4ac9f2/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 --- awx/sso/backends.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/awx/sso/backends.py b/awx/sso/backends.py index 4f4f9bea4f..b1304cce84 100644 --- a/awx/sso/backends.py +++ b/awx/sso/backends.py @@ -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.