Repository navigation
gh-142732: Prevent reentrancy in itertools.zip_longest
#150675
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0cb2754
f6706b5
5a4f05a
54c5188
0fda862
90803c8
54d9265
796461f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Now :func:`itertools.zip_longest` raises a :exc:`ValueError` when a reentrancy is detected. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3847,6 +3847,7 @@ struct ziplongestobject { | |
| PyObject *ittuple; /* tuple of iterators */ | ||
| PyObject *result; | ||
| PyObject *fillvalue; | ||
| uint8_t running; | ||
| }; | ||
|
|
||
| #define ziplongestobject_CAST(op) ((ziplongestobject *)(op)) | ||
|
|
@@ -3916,6 +3917,7 @@ zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
| lz->numactive = tuplesize; | ||
| lz->result = result; | ||
| lz->fillvalue = Py_NewRef(fillvalue); | ||
| lz->running = 0; | ||
| return (PyObject *)lz; | ||
| } | ||
|
|
||
|
|
@@ -3960,10 +3962,21 @@ zip_longest_next_impl(ziplongestobject *self) | |
| PyObject *item; | ||
| PyObject *olditem; | ||
|
|
||
| if (tuplesize == 0) | ||
| return NULL; | ||
| if (lz->numactive == 0) | ||
| if (lz->running == 1) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I have no strong opinion on the type of error, but lets make it an informed decision and then be consistent. @rhettinger
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eendebakpt @rhettinger Has there been any update yet on what error is best to raise? |
||
| "zip_longest() iterator already executing"); | ||
| return NULL; | ||
| } | ||
| lz->running = 1; | ||
|
|
||
| if (tuplesize == 0) { | ||
| result = NULL; | ||
| goto done; | ||
| } | ||
| if (lz->numactive == 0) { | ||
| result = NULL; | ||
| goto done; | ||
| } | ||
| if (_PyObject_IsUniquelyReferenced(result)) { | ||
| Py_INCREF(result); | ||
| for (i=0 ; i < tuplesize ; i++) { | ||
|
|
@@ -3977,7 +3990,8 @@ zip_longest_next_impl(ziplongestobject *self) | |
| if (lz->numactive == 0 || PyErr_Occurred()) { | ||
| lz->numactive = 0; | ||
| Py_DECREF(result); | ||
| return NULL; | ||
| result = NULL; | ||
| goto done; | ||
| } else { | ||
| item = Py_NewRef(lz->fillvalue); | ||
| PyTuple_SET_ITEM(lz->ittuple, i, NULL); | ||
|
|
@@ -3994,8 +4008,9 @@ zip_longest_next_impl(ziplongestobject *self) | |
| _PyTuple_Recycle(result); | ||
| } else { | ||
| result = PyTuple_New(tuplesize); | ||
| if (result == NULL) | ||
| return NULL; | ||
| if (result == NULL) { | ||
| goto done; | ||
| } | ||
| for (i=0 ; i < tuplesize ; i++) { | ||
| it = PyTuple_GET_ITEM(lz->ittuple, i); | ||
| if (it == NULL) { | ||
|
|
@@ -4007,7 +4022,8 @@ zip_longest_next_impl(ziplongestobject *self) | |
| if (lz->numactive == 0 || PyErr_Occurred()) { | ||
| lz->numactive = 0; | ||
| Py_DECREF(result); | ||
| return NULL; | ||
| result = NULL; | ||
| goto done; | ||
| } else { | ||
| item = Py_NewRef(lz->fillvalue); | ||
| PyTuple_SET_ITEM(lz->ittuple, i, NULL); | ||
|
|
@@ -4018,6 +4034,8 @@ zip_longest_next_impl(ziplongestobject *self) | |
| PyTuple_SET_ITEM(result, i, item); | ||
| } | ||
| } | ||
| done: | ||
| lz->running = 0; | ||
| return result; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.