python-dev  

Re: Segfaults in ConnectionHander (Possible Solution)

Graham Dumpleton
Mon, 30 Jan 2006 17:59:27 -0800

Graham Dumpleton wrote ..
> Returning back up to _conn_read() in mod_python source code, we have
> where core_input_filter() was called ap_get_brigade():
> 
>     Py_BEGIN_ALLOW_THREADS;
>     rc = ap_get_brigade(c->input_filters, bb, mode, APR_BLOCK_READ, bufsize);
>     Py_END_ALLOW_THREADS;
>     
>     if (! APR_STATUS_IS_SUCCESS(rc)) {
>         PyErr_SetObject(PyExc_IOError, 
>                         PyString_FromString("Connection read error"));
>         return NULL;
>     }
> 
> Since APR_SUCCESS was returned and assigned to "rc", no problem is detected.
> 
> The code which follows then assumes that the first bucket in the bucket
> brigade actually contains valid data, when in fact the first bucket is
> actually
> crap as nothing was done to set up a valid bucket since EAGAIN was returned.
> As a consequence it crashes.
> 
> Thus in summary, _conn_read() doesn't cater in any way for the possibility
> that the initial socket read may have failed because of EAGAIN and thus
> the bucket is bogus. The problem is, how is it mean't to know this if the
> value APR_SUCCESS is returned by ap_get_brigade().

Extending the above code as:

    Py_BEGIN_ALLOW_THREADS;
    rc = ap_get_brigade(c->input_filters, bb, mode, APR_BLOCK_READ, bufsize);
    Py_END_ALLOW_THREADS;

    if (! APR_STATUS_IS_SUCCESS(rc)) {
        PyErr_SetObject(PyExc_IOError,
                        PyString_FromString("Connection read error"));
        return NULL;
    }

    /* Return empty string if no buckets. Can be caused by EAGAIN. */
    if (APR_BRIGADE_EMPTY(bb)) {
        return PyString_FromString("");
    }

seems to fix the problem. Ie., use call to APR_BRIGADE_EMPTY(bb) to check
whether any new buckets added and returning empty string if not.

Can someone else seeing this issue try this fix and see if the tests then
work.

Graham