|
2 | 2 | #define PY_SSIZE_T_CLEAN |
3 | 3 | #include "Python.h" |
4 | 4 | #include "pycore_tupleobject.h" |
| 5 | +#include "pycore_object.h" // _PyObject_GC_TRACK() |
5 | 6 | #include <stddef.h> // offsetof() |
6 | 7 |
|
7 | 8 | /* Itertools module written and maintained |
@@ -2245,6 +2246,11 @@ product_next(productobject *lz) |
2245 | 2246 | lz->result = result; |
2246 | 2247 | Py_DECREF(old_result); |
2247 | 2248 | } |
| 2249 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 2250 | + // recycling it, make sure it's tracked again: |
| 2251 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 2252 | + _PyObject_GC_TRACK(result); |
| 2253 | + } |
2248 | 2254 | /* Now, we've got the only copy so we can update it in-place */ |
2249 | 2255 | assert (npools==0 || Py_REFCNT(result) == 1); |
2250 | 2256 |
|
@@ -2568,6 +2574,11 @@ combinations_next(combinationsobject *co) |
2568 | 2574 | co->result = result; |
2569 | 2575 | Py_DECREF(old_result); |
2570 | 2576 | } |
| 2577 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 2578 | + // recycling it, make sure it's tracked again: |
| 2579 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 2580 | + _PyObject_GC_TRACK(result); |
| 2581 | + } |
2571 | 2582 | /* Now, we've got the only copy so we can update it in-place |
2572 | 2583 | * CPython's empty tuple is a singleton and cached in |
2573 | 2584 | * PyTuple's freelist. |
@@ -2902,6 +2913,11 @@ cwr_next(cwrobject *co) |
2902 | 2913 | co->result = result; |
2903 | 2914 | Py_DECREF(old_result); |
2904 | 2915 | } |
| 2916 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 2917 | + // recycling it, make sure it's tracked again: |
| 2918 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 2919 | + _PyObject_GC_TRACK(result); |
| 2920 | + } |
2905 | 2921 | /* Now, we've got the only copy so we can update it in-place CPython's |
2906 | 2922 | empty tuple is a singleton and cached in PyTuple's freelist. */ |
2907 | 2923 | assert(r == 0 || Py_REFCNT(result) == 1); |
@@ -3246,6 +3262,11 @@ permutations_next(permutationsobject *po) |
3246 | 3262 | po->result = result; |
3247 | 3263 | Py_DECREF(old_result); |
3248 | 3264 | } |
| 3265 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 3266 | + // recycling it, make sure it's tracked again: |
| 3267 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 3268 | + _PyObject_GC_TRACK(result); |
| 3269 | + } |
3249 | 3270 | /* Now, we've got the only copy so we can update it in-place */ |
3250 | 3271 | assert(r == 0 || Py_REFCNT(result) == 1); |
3251 | 3272 |
|
@@ -4515,6 +4536,11 @@ zip_longest_next(ziplongestobject *lz) |
4515 | 4536 | PyTuple_SET_ITEM(result, i, item); |
4516 | 4537 | Py_DECREF(olditem); |
4517 | 4538 | } |
| 4539 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 4540 | + // recycling it, make sure it's tracked again: |
| 4541 | + if (!_PyObject_GC_IS_TRACKED(result)) { |
| 4542 | + _PyObject_GC_TRACK(result); |
| 4543 | + } |
4518 | 4544 | } else { |
4519 | 4545 | result = PyTuple_New(tuplesize); |
4520 | 4546 | if (result == NULL) |
|
0 commit comments