|
3 | 3 | #include "Python.h" |
4 | 4 | #include "pycore_tupleobject.h" |
5 | 5 | #include "structmember.h" |
| 6 | +#include "pycore_object.h" // _PyObject_GC_TRACK() |
6 | 7 |
|
7 | 8 | /* Itertools module written and maintained |
8 | 9 | by Raymond D. Hettinger <python@rcn.com> |
@@ -2255,6 +2256,11 @@ product_next(productobject *lz) |
2255 | 2256 | lz->result = result; |
2256 | 2257 | Py_DECREF(old_result); |
2257 | 2258 | } |
| 2259 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 2260 | + // recycling it, make sure it's tracked again: |
| 2261 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 2262 | + _PyObject_GC_TRACK(result); |
| 2263 | + } |
2258 | 2264 | /* Now, we've got the only copy so we can update it in-place */ |
2259 | 2265 | assert (npools==0 || Py_REFCNT(result) == 1); |
2260 | 2266 |
|
@@ -2580,6 +2586,11 @@ combinations_next(combinationsobject *co) |
2580 | 2586 | co->result = result; |
2581 | 2587 | Py_DECREF(old_result); |
2582 | 2588 | } |
| 2589 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 2590 | + // recycling it, make sure it's tracked again: |
| 2591 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 2592 | + _PyObject_GC_TRACK(result); |
| 2593 | + } |
2583 | 2594 | /* Now, we've got the only copy so we can update it in-place |
2584 | 2595 | * CPython's empty tuple is a singleton and cached in |
2585 | 2596 | * PyTuple's freelist. |
@@ -2916,6 +2927,11 @@ cwr_next(cwrobject *co) |
2916 | 2927 | co->result = result; |
2917 | 2928 | Py_DECREF(old_result); |
2918 | 2929 | } |
| 2930 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 2931 | + // recycling it, make sure it's tracked again: |
| 2932 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 2933 | + _PyObject_GC_TRACK(result); |
| 2934 | + } |
2919 | 2935 | /* Now, we've got the only copy so we can update it in-place CPython's |
2920 | 2936 | empty tuple is a singleton and cached in PyTuple's freelist. */ |
2921 | 2937 | assert(r == 0 || Py_REFCNT(result) == 1); |
@@ -3259,6 +3275,11 @@ permutations_next(permutationsobject *po) |
3259 | 3275 | po->result = result; |
3260 | 3276 | Py_DECREF(old_result); |
3261 | 3277 | } |
| 3278 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 3279 | + // recycling it, make sure it's tracked again: |
| 3280 | + else if (!_PyObject_GC_IS_TRACKED(result)) { |
| 3281 | + _PyObject_GC_TRACK(result); |
| 3282 | + } |
3262 | 3283 | /* Now, we've got the only copy so we can update it in-place */ |
3263 | 3284 | assert(r == 0 || Py_REFCNT(result) == 1); |
3264 | 3285 |
|
@@ -4536,6 +4557,11 @@ zip_longest_next(ziplongestobject *lz) |
4536 | 4557 | PyTuple_SET_ITEM(result, i, item); |
4537 | 4558 | Py_DECREF(olditem); |
4538 | 4559 | } |
| 4560 | + // bpo-42536: The GC may have untracked this result tuple. Since we're |
| 4561 | + // recycling it, make sure it's tracked again: |
| 4562 | + if (!_PyObject_GC_IS_TRACKED(result)) { |
| 4563 | + _PyObject_GC_TRACK(result); |
| 4564 | + } |
4539 | 4565 | } else { |
4540 | 4566 | result = PyTuple_New(tuplesize); |
4541 | 4567 | if (result == NULL) |
|
0 commit comments