Skip to content

Commit

Permalink
pythongh-127065: Make methodcaller thread-safe in free threading build
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
colesbury committed Nov 21, 2024
1 parent 3926842 commit a4b7749
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix crash when calling a :func:`operator.methodcaller` instance from
multiple threads in the free threading build.
9 changes: 9 additions & 0 deletions Modules/_operator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,7 @@ typedef struct {
vectorcallfunc vectorcall;
} methodcallerobject;

#ifndef Py_GIL_DISABLED
static int _methodcaller_initialize_vectorcall(methodcallerobject* mc)
{
PyObject* args = mc->xargs;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit a4b7749

Please sign in to comment.