https://github.com/python/cpython/commit/f83ca6962af973fff6a3124f4bd3d45fea4dd5b8
commit: f83ca6962af973fff6a3124f4bd3d45fea4dd5b8
branch: main
author: Sam Gross <[email protected]>
committer: colesbury <[email protected]>
date: 2024-11-22T09:21:59-05:00
summary:
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.
files:
A Misc/NEWS.d/next/Library/2024-11-21-16-23-16.gh-issue-127065.cfL1zd.rst
M Modules/_operator.c
diff --git
a/Misc/NEWS.d/next/Library/2024-11-21-16-23-16.gh-issue-127065.cfL1zd.rst
b/Misc/NEWS.d/next/Library/2024-11-21-16-23-16.gh-issue-127065.cfL1zd.rst
new file mode 100644
index 00000000000000..83457da467ffa9
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-11-21-16-23-16.gh-issue-127065.cfL1zd.rst
@@ -0,0 +1,2 @@
+Fix crash when calling a :func:`operator.methodcaller` instance from
+multiple threads in the free threading build.
diff --git a/Modules/_operator.c b/Modules/_operator.c
index 7e0d1f3df87e4d..6c1945174ab7cd 100644
--- a/Modules/_operator.c
+++ b/Modules/_operator.c
@@ -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;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]