From 6f7279c4b1db894eb431c182ea9df5d665b3f726 Mon Sep 17 00:00:00 2001 From: Daniel Tao Date: Fri, 22 Sep 2017 07:43:00 -0500 Subject: [PATCH] Refs #28593 -- Made URLResolver._populate() more resilient to signal interrupts. _populate() sets the populating attribute to prevent infinite recursion in case a urlconf includes itself. The flag is a threadlocal to avoid a race condition [1] where one thread sets the flag and another checks it, then proceeds to access data that's supposed to be populated (e.g. _reverse_dict) but isn't yet. The potential still exists for a thread to set the threadlocal, then be interrupted by a signal such as SIGALRM and raise before resetting the threadlocal flag. In this scenario, subsequent calls to _populate() in the same thread will short-circuit erroneously. The bulk of the method was already wrapped in a try/finally in df41b5a, but since a signal interrupt can occur at any line executed by the interpreter, this moves up the try to ensure threadlocal gets reset. [1]: https://groups.google.com/d/msg/django-developers/D_bIeinKHjE/4NmVQUJqAgAJ --- django/urls/resolvers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py index f91e821b387..9ee96d38d1f 100644 --- a/django/urls/resolvers.py +++ b/django/urls/resolvers.py @@ -398,12 +398,12 @@ class URLResolver: # thread-local variable. if getattr(self._local, 'populating', False): return - self._local.populating = True - lookups = MultiValueDict() - namespaces = {} - apps = {} - language_code = get_language() try: + self._local.populating = True + lookups = MultiValueDict() + namespaces = {} + apps = {} + language_code = get_language() for url_pattern in reversed(self.url_patterns): p_pattern = url_pattern.pattern.regex.pattern if p_pattern.startswith('^'):