Exploiting Dual Core's with Py_NewInterpreter's separated GIL ?

"Martin v. Löwis" martin at v.loewis.de
Tue Nov 7 13:11:47 EST 2006


Ross Ridge schrieb:
> The thread that shares it increments the reference count before passing
> its address to directly another thread or indirectly through a shared
> container.

To make a specific example, consider this fragment from
Objects/fileobject.c:

static PyObject *
file_repr(PyFileObject *f)
{
        if (PyUnicode_Check(f->f_name)) {
...

Now, assume there wasn't a GIL protecting this all, and also
assume f_name was a mutable member (which it currently isn't).

Then, this access wouldn't be thread-safe: This code roughly
translates to

    reg_x = f->f_name
    push reg_x
    call PyUnicode_Check (assuming this was a function and
    not a macro)

Meanwhile, another process might perform

    old = f->f_name;
    f->f_name = new;
    Py_DECREF(old);

i.e. change the file name. Now, it might be that they
interleave this way:

    reg_x = f->f_name
    old = f->f_name
    f->f_name = new
    Py_DECREF_old
    push reg_x
    call PyUnicode_Check

which would now operate on a deallocated object.

To fix this, one might think that we need

   Py_INCREF(f->f_name)
   if(Py_UnicodeCheck(f->f_name))
   ...
   Py_DECREF(f->f_name)

However, this would not help, because the
first incref translates to

   reg_x = f->f_name
   LOCK INC f->ob_refcnt

which again leaves a race condition where the
INCREF operation comes "too late".

How would you propose to fix file_repr to prevent such
a race condition?

Regards,
Martin



More information about the Python-list mailing list