mirror of
https://github.com/python/cpython.git
synced 2025-11-09 14:06:30 +00:00
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:
parent
3c770e3f09
commit
f83ca6962a
2 changed files with 11 additions and 0 deletions
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix crash when calling a :func:`operator.methodcaller` instance from
|
||||||
|
multiple threads in the free threading build.
|
||||||
|
|
@ -1602,6 +1602,7 @@ typedef struct {
|
||||||
vectorcallfunc vectorcall;
|
vectorcallfunc vectorcall;
|
||||||
} methodcallerobject;
|
} methodcallerobject;
|
||||||
|
|
||||||
|
#ifndef Py_GIL_DISABLED
|
||||||
static int _methodcaller_initialize_vectorcall(methodcallerobject* mc)
|
static int _methodcaller_initialize_vectorcall(methodcallerobject* mc)
|
||||||
{
|
{
|
||||||
PyObject* args = mc->xargs;
|
PyObject* args = mc->xargs;
|
||||||
|
|
@ -1664,6 +1665,7 @@ methodcaller_vectorcall(
|
||||||
(PyTuple_GET_SIZE(mc->xargs)) | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
(PyTuple_GET_SIZE(mc->xargs)) | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||||
mc->vectorcall_kwnames);
|
mc->vectorcall_kwnames);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* AC 3.5: variable number of arguments, not currently support by AC */
|
/* 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;
|
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;
|
mc->vectorcall = (vectorcallfunc)methodcaller_vectorcall;
|
||||||
|
#endif
|
||||||
|
|
||||||
PyObject_GC_Track(mc);
|
PyObject_GC_Track(mc);
|
||||||
return (PyObject *)mc;
|
return (PyObject *)mc;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue