Skip to content

Commit 17eb035

Browse files
authored
gh-145446: Add critical section in functools module for PyDict_Next (GH-145487)
1 parent 7836ecc commit 17eb035

File tree

2 files changed

+13
-2
lines changed

2 files changed

+13
-2
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Now :mod:`functools` is safer in free-threaded build when using keywords in :func:`functools.partial`

Modules/_functoolsmodule.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,15 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
492492
/* Copy pto_keywords with overlapping call keywords merged
493493
* Note, tail is already coppied. */
494494
Py_ssize_t pos = 0, i = 0;
495-
while (PyDict_Next(n_merges ? pto_kw_merged : pto->kw, &pos, &key, &val)) {
495+
PyObject *keyword_dict = n_merges ? pto_kw_merged : pto->kw;
496+
Py_BEGIN_CRITICAL_SECTION(keyword_dict);
497+
while (PyDict_Next(keyword_dict, &pos, &key, &val)) {
496498
assert(i < pto_nkwds);
497499
PyTuple_SET_ITEM(tot_kwnames, i, Py_NewRef(key));
498500
stack[tot_nargs + i] = val;
499501
i++;
500502
}
503+
Py_END_CRITICAL_SECTION();
501504
assert(i == pto_nkwds);
502505
Py_XDECREF(pto_kw_merged);
503506

@@ -728,16 +731,23 @@ partial_repr(PyObject *self)
728731
}
729732
}
730733
/* Pack keyword arguments */
734+
int error = 0;
735+
Py_BEGIN_CRITICAL_SECTION(kw);
731736
for (i = 0; PyDict_Next(kw, &i, &key, &value);) {
732737
/* Prevent key.__str__ from deleting the value. */
733738
Py_INCREF(value);
734739
Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
735740
key, value));
736741
Py_DECREF(value);
737742
if (arglist == NULL) {
738-
goto done;
743+
error = 1;
744+
break;
739745
}
740746
}
747+
Py_END_CRITICAL_SECTION();
748+
if (error) {
749+
goto done;
750+
}
741751

742752
mod = PyType_GetModuleName(Py_TYPE(pto));
743753
if (mod == NULL) {

0 commit comments

Comments
 (0)