I have found an incomplete-initialization bug the WSGIHandler when 
running under Apache mpm_worker with mod_wsgi.

On the first request the WSGIHandler.__call__(...), we set up the 
middleware.  There is a lock wrapping the load of the middleware, but 
the logic still allows incomplete initialization on other threads.  
Below is the block of code in question from django/core/handlers/wsgi.py 
(line 226):

        if self._request_middleware is None:
            self.initLock.acquire()
            # Check that middleware is still uninitialised.
            if self._request_middleware is None:
                self.load_middleware()
            self.initLock.release()

Example:

    1. Initial start or restart of the Apache instance
    2. Thread T1 - a request comes in.  self._request_middleware is None
    3. Thread T1 - acquires the self.initLock, calls self.load_middleware()
    4. Thread T2 - a request comes in (T1 is part of the way through 
self.load_middleware()
    5. Thread T2 - self._request_middleware is not None, but it's not 
completely loaded either, continues with the request
    6. Thread T1 - completes self.load_middleware(), release the lock

The problem is the assignment of self._request_middleware is not atomic 
(it is created as an empty list and populated with append() in a loop.  
To fix this, we need an atomic assignment.  I initially thought about 
changing load_middleware() to build the _request_middleware array in a 
local variable and then doing a single assignment to save it to 
self._request_middleware.  While this would solve the problem, I thought 
that having the initialization test in WSGIHandler.__call__() test for 
what is essentially a side effect of self.load_middleware() is error prone.

So, my proposed fix is to add a flag in WSGIHandler and then test for 
that flag in __call__().  I implemented this in our custom WSGI handler 
replacement and it worked perfectly.  I will submit a ticket with patch 
to Django if the group agrees.  Here is my fix:

    WSGIHandler.__init__(self):
        BaseHandler.__init__(self)
        self._middleware_loaded = False

    WSGIHandler.__call__(...):
        ...
        if not self._middleware_loaded:
            self.initLock.acquire()
            # Check that middleware is still uninitialised.
            if not self._middleware_loaded:
                self.load_middleware()
                self._middleware_loaded = True
            self.initLock.release()
        ...

Travis
Propeller.com
    

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to