summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorBrandt Bucher <brandtbucher@gmail.com>2020-12-05 03:45:57 (GMT)
committerGitHub <noreply@github.com>2020-12-05 03:45:57 (GMT)
commit226a012d1cd61f42ecd3056c554922f359a1a35d (patch)
tree86407049a5d2c22b0ce8626407ca106eb3c26afd /Modules
parent2de5097ba4c50eba90df55696a7b2e74c93834d4 (diff)
downloadcpython-226a012d1cd61f42ecd3056c554922f359a1a35d.zip
cpython-226a012d1cd61f42ecd3056c554922f359a1a35d.tar.gz
cpython-226a012d1cd61f42ecd3056c554922f359a1a35d.tar.bz2
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.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_functoolsmodule.c6
-rw-r--r--Modules/itertoolsmodule.c26
2 files changed, 32 insertions, 0 deletions
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index ff03c33..621b721 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -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);
+ }
}
}
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index 7144856..293735a 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -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)