[Python-3000] uuid creation not thread-safe?

lcaamano lcaamano at gmail.com
Sun Jul 29 03:04:29 CEST 2007


On Jul 20, 1:52 pm, "Guido van Rossum" <gu... at python.org> wrote:
> I discovered what appears to be a thread-unsafety inuuid.py. This is
> in the trunk as well as in 3.x; I'm using the trunk here for easy
> reference. There's some code around like 395:
>
>     import ctypes, ctypes.util
>     _buffer = ctypes.create_string_buffer(16)
>
> This creates a *global* buffer which is used as the output parameter
> to later calls to _uuid_generate_random() and _uuid_generate_time().
> For example, around line 481, in uuid1():
>
>         _uuid_generate_time(_buffer)
>         returnUUID(bytes=_buffer.raw)
>
> Clearly if two threads do this simultaneously they are overwriting
> _buffer in unpredictable order. There are a few other occurrences of
> this too.
>
> I find it somewhat disturbing that what seems a fairly innocent
> function that doesn't *appear* to have global state is nevertheless
> not thread-safe. Would it be wise to fix this, e.g. by allocating a
> fresh output buffer inside uuid1() and other callers?
>


I didn't find any reply to this, which is odd, so forgive me if it's
old news.

I agree with you that it's not thread safe and that a local buffer in
the stack should fix it.

Just for reference, the thread-safe uuid extension we've been using
since python 2.1, which I don't recall where we borrow it from, uses a
local buffer in the stack.  It looks like this:

-----begin uuid.c--------------

static char uuid__doc__ [] =
"DCE compatible Universally Unique Identifier module";

#include "Python.h"
#include <uuid/uuid.h>

static char uuidgen__doc__ [] =
"Create a new DCE compatible UUID value";

static PyObject *
uuidgen(void)
{
uuid_t out;
char buf[48];

    uuid_generate(out);
    uuid_unparse(out, buf);
    return PyString_FromString(buf);
}

static PyMethodDef uuid_methods[] = {
    {"uuidgen", uuidgen, 0, uuidgen__doc__},
    {NULL,      NULL}        /* Sentinel */
};

DL_EXPORT(void)
inituuid(void)
{
    Py_InitModule4("uuid",
               uuid_methods,
               uuid__doc__,
               (PyObject *)NULL,
               PYTHON_API_VERSION);
}

-----end uuid.c--------------


It also seems that using uuid_generate()/uuid_unparse() should be
faster than using uuid_generate_random() and then creating a python
object to call its __str__ method.  If so, it would be nice if the
uuid.py module also provided equivalent fast versions that returned
strings instead of objects.


--
Luis P Caamano
Atlanta, GA, USA



More information about the Python-3000 mailing list