Skip to content

Commit f83ca69

Browse files
authored
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.
1 parent 3c770e3 commit f83ca69

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash when calling a :func:`operator.methodcaller` instance from
2+
multiple threads in the free threading build.

Modules/_operator.c

+9
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,7 @@ typedef struct {
16021602
vectorcallfunc vectorcall;
16031603
} methodcallerobject;
16041604

1605+
#ifndef Py_GIL_DISABLED
16051606
static int _methodcaller_initialize_vectorcall(methodcallerobject* mc)
16061607
{
16071608
PyObject* args = mc->xargs;
@@ -1664,6 +1665,7 @@ methodcaller_vectorcall(
16641665
(PyTuple_GET_SIZE(mc->xargs)) | PY_VECTORCALL_ARGUMENTS_OFFSET,
16651666
mc->vectorcall_kwnames);
16661667
}
1668+
#endif
16671669

16681670

16691671
/* AC 3.5: variable number of arguments, not currently support by AC */
@@ -1703,7 +1705,14 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
17031705
mc->vectorcall_args = 0;
17041706

17051707

1708+
#ifdef Py_GIL_DISABLED
1709+
// gh-127065: The current implementation of methodcaller_vectorcall
1710+
// is not thread-safe because it modifies the `vectorcall_args` array,
1711+
// which is shared across calls.
1712+
mc->vectorcall = NULL;
1713+
#else
17061714
mc->vectorcall = (vectorcallfunc)methodcaller_vectorcall;
1715+
#endif
17071716

17081717
PyObject_GC_Track(mc);
17091718
return (PyObject *)mc;

0 commit comments

Comments
 (0)