gh-127065: Make `methodcaller` thread-safe in free threading build (#127109)

The `methodcaller` C vectorcall implementation uses an arguments array
that is shared across calls. The first argument is modified on every
invocation. This isn't thread-safe in the free threading build. I think
it's also not safe in general, but for now just disable it in the free
threading build.
This commit is contained in:
Sam Gross 2024-11-22 14:21:59 +00:00 committed by GitHub
parent 3c770e3f09
commit f83ca6962a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 11 additions and 0 deletions

View File

@ -0,0 +1,2 @@
Fix crash when calling a :func:`operator.methodcaller` instance from
multiple threads in the free threading build.

View File

@ -1602,6 +1602,7 @@ typedef struct {
vectorcallfunc vectorcall;
} methodcallerobject;
#ifndef Py_GIL_DISABLED
static int _methodcaller_initialize_vectorcall(methodcallerobject* mc)
{
PyObject* args = mc->xargs;
@ -1664,6 +1665,7 @@ methodcaller_vectorcall(
(PyTuple_GET_SIZE(mc->xargs)) | PY_VECTORCALL_ARGUMENTS_OFFSET,
mc->vectorcall_kwnames);
}
#endif
/* AC 3.5: variable number of arguments, not currently support by AC */
@ -1703,7 +1705,14 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
mc->vectorcall_args = 0;
#ifdef Py_GIL_DISABLED
// gh-127065: The current implementation of methodcaller_vectorcall
// is not thread-safe because it modifies the `vectorcall_args` array,
// which is shared across calls.
mc->vectorcall = NULL;
#else
mc->vectorcall = (vectorcallfunc)methodcaller_vectorcall;
#endif
PyObject_GC_Track(mc);
return (PyObject *)mc;