-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-101765: Fix SystemError / segmentation fault in iter __reduce__
when internal access of builtins.__dict__
exhausts the iterator
#101769
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
Changes from 20 commits
f256afe
6b4faad
a6d6211
4ccf427
c2c9cfb
e2989d9
71960a8
efa0540
c5abb14
45522c6
4f5fc19
049a8dd
ef4f955
7d4afb0
8e4418d
d8ced8e
178b8ea
49ba8c3
93854e1
98ec3c6
e661495
19ab9c6
9b664c2
c67b11a
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 @@ | ||
Fix SystemError / segmentation fault in iter ``__reduce__`` when calling ``__builtins__.__dict__["iter"]`` mutates the iter object. | ||
carljm marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2391,11 +2391,17 @@ PyDoc_STRVAR(length_hint_doc, | |
static PyObject * | ||
bytearrayiter_reduce(bytesiterobject *it, PyObject *Py_UNUSED(ignored)) | ||
{ | ||
PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); | ||
|
||
/* _PyEval_GetBuiltin can invoke arbitrary code. | ||
* calls must be *before* access of `it` pointers, | ||
* since C parameter eval order is undefined. | ||
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 think parameter eval order isn't the issue and shouldn't be mentioned. The problem is that the For example, this code would also be buggy:
The parameter evaluation order makes things a bit more unpredictable, but the bug is that the 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. Hm, yeah. I think this might be better?
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. sounds good! 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. Updated all comments to the above in 9b664c2 |
||
* see issue #101765 */ | ||
|
||
if (it->it_seq != NULL) { | ||
return Py_BuildValue("N(O)n", _PyEval_GetBuiltin(&_Py_ID(iter)), | ||
it->it_seq, it->it_index); | ||
return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); | ||
} else { | ||
return Py_BuildValue("N(())", _PyEval_GetBuiltin(&_Py_ID(iter))); | ||
return Py_BuildValue("N(())", iter); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3444,18 +3444,23 @@ listiter_reduce_general(void *_it, int forward) | |
{ | ||
PyObject *list; | ||
|
||
/* _PyEval_GetBuiltin can invoke arbitrary code. | ||
* calls must be *before* access of `_it` pointers, | ||
* since C parameter eval order is undefined. | ||
* see issue #101765 */ | ||
|
||
/* the objects are not the same, index is of different types! */ | ||
if (forward) { | ||
PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter)); | ||
_PyListIterObject *it = (_PyListIterObject *)_it; | ||
if (it->it_seq) { | ||
return Py_BuildValue("N(O)n", _PyEval_GetBuiltin(&_Py_ID(iter)), | ||
it->it_seq, it->it_index); | ||
return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index); | ||
} | ||
} else { | ||
PyObject *reversed = _PyEval_GetBuiltin(&_Py_ID(reversed)); | ||
ionite34 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
listreviterobject *it = (listreviterobject *)_it; | ||
if (it->it_seq) { | ||
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. If 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. Good point, but doesn't that mean the old code also leaked references? I'll prepare a PR to fix this now. 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. Oh wait, the N code to Py_BuildValue steals a reference, so the previous code was right in terms of refcounting. |
||
return Py_BuildValue("N(O)n", _PyEval_GetBuiltin(&_Py_ID(reversed)), | ||
it->it_seq, it->it_index); | ||
return Py_BuildValue("N(O)n", reversed, it->it_seq, it->it_index); | ||
} | ||
} | ||
/* empty iterator, create an empty list */ | ||
|
Uh oh!
There was an error while loading. Please reload this page.