mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
bpo-42536: GC track recycled tuples (GH-23623)
Several built-in and standard library types now ensure that their internal result tuples are always tracked by the garbage collector: - collections.OrderedDict.items - dict.items - enumerate - functools.reduce - itertools.combinations - itertools.combinations_with_replacement - itertools.permutations - itertools.product - itertools.zip_longest - zip Previously, they could have become untracked by a prior garbage collection.
This commit is contained in:
parent
2de5097ba4
commit
226a012d1c
12 changed files with 192 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
|||
#include "Python.h"
|
||||
#include "pycore_long.h" // _PyLong_GetZero()
|
||||
#include "pycore_object.h" // _PyObject_GC_TRACK
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
#include "pycore_tuple.h" // _PyTuple_ITEMS()
|
||||
#include "structmember.h" // PyMemberDef
|
||||
|
@ -673,6 +674,11 @@ functools_reduce(PyObject *self, PyObject *args)
|
|||
if ((result = PyObject_Call(func, args, NULL)) == NULL) {
|
||||
goto Fail;
|
||||
}
|
||||
// bpo-42536: The GC may have untracked this args tuple. Since we're
|
||||
// recycling it, make sure it's tracked again:
|
||||
if (!_PyObject_GC_IS_TRACKED(args)) {
|
||||
_PyObject_GC_TRACK(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
#include "pycore_long.h" // _PyLong_GetZero()
|
||||
#include "pycore_object.h" // _PyObject_GC_TRACK()
|
||||
#include "pycore_tuple.h" // _PyTuple_ITEMS()
|
||||
#include <stddef.h> // offsetof()
|
||||
|
||||
|
@ -2378,6 +2379,11 @@ product_next(productobject *lz)
|
|||
lz->result = result;
|
||||
Py_DECREF(old_result);
|
||||
}
|
||||
// bpo-42536: The GC may have untracked this result tuple. Since we're
|
||||
// recycling it, make sure it's tracked again:
|
||||
else if (!_PyObject_GC_IS_TRACKED(result)) {
|
||||
_PyObject_GC_TRACK(result);
|
||||
}
|
||||
/* Now, we've got the only copy so we can update it in-place */
|
||||
assert (npools==0 || Py_REFCNT(result) == 1);
|
||||
|
||||
|
@ -2701,6 +2707,11 @@ combinations_next(combinationsobject *co)
|
|||
co->result = result;
|
||||
Py_DECREF(old_result);
|
||||
}
|
||||
// bpo-42536: The GC may have untracked this result tuple. Since we're
|
||||
// recycling it, make sure it's tracked again:
|
||||
else if (!_PyObject_GC_IS_TRACKED(result)) {
|
||||
_PyObject_GC_TRACK(result);
|
||||
}
|
||||
/* Now, we've got the only copy so we can update it in-place
|
||||
* CPython's empty tuple is a singleton and cached in
|
||||
* PyTuple's freelist.
|
||||
|
@ -3035,6 +3046,11 @@ cwr_next(cwrobject *co)
|
|||
co->result = result;
|
||||
Py_DECREF(old_result);
|
||||
}
|
||||
// bpo-42536: The GC may have untracked this result tuple. Since we're
|
||||
// recycling it, make sure it's tracked again:
|
||||
else if (!_PyObject_GC_IS_TRACKED(result)) {
|
||||
_PyObject_GC_TRACK(result);
|
||||
}
|
||||
/* Now, we've got the only copy so we can update it in-place CPython's
|
||||
empty tuple is a singleton and cached in PyTuple's freelist. */
|
||||
assert(r == 0 || Py_REFCNT(result) == 1);
|
||||
|
@ -3379,6 +3395,11 @@ permutations_next(permutationsobject *po)
|
|||
po->result = result;
|
||||
Py_DECREF(old_result);
|
||||
}
|
||||
// bpo-42536: The GC may have untracked this result tuple. Since we're
|
||||
// recycling it, make sure it's tracked again:
|
||||
else if (!_PyObject_GC_IS_TRACKED(result)) {
|
||||
_PyObject_GC_TRACK(result);
|
||||
}
|
||||
/* Now, we've got the only copy so we can update it in-place */
|
||||
assert(r == 0 || Py_REFCNT(result) == 1);
|
||||
|
||||
|
@ -4649,6 +4670,11 @@ zip_longest_next(ziplongestobject *lz)
|
|||
PyTuple_SET_ITEM(result, i, item);
|
||||
Py_DECREF(olditem);
|
||||
}
|
||||
// bpo-42536: The GC may have untracked this result tuple. Since we're
|
||||
// recycling it, make sure it's tracked again:
|
||||
if (!_PyObject_GC_IS_TRACKED(result)) {
|
||||
_PyObject_GC_TRACK(result);
|
||||
}
|
||||
} else {
|
||||
result = PyTuple_New(tuplesize);
|
||||
if (result == NULL)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue