Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
gh-89189: More compact range iterator#27986
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
bedevere-bot commentedSep 8, 2021
serhiy-storchaka commentedMay 3, 2022
See also#28176. |
iritkatriel left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This has merge conflicts now.
bedevere-bot commentedNov 26, 2022
When you're done making the requested changes, leave the comment: |
gvanrossum left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Nice! Just a few nits.
| returnPy_BuildValue("N(N)O",_PyEval_GetBuiltin(&_Py_ID(iter)), | ||
| range,Py_None); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm not sure we care, but we might -- am I right that this writes pickles that can't be read by 3.11 or before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
No, absolutely no. I would never propose such change.
Internals will be different, but the unpickled iterator wil produce the same values.
Objects/rangeobject.c Outdated
| PyObject*new_len=PyNumber_Subtract(r->len,state); | ||
| if (new_len==NULL) | ||
| returnNULL; | ||
| Py_SETREF(r->len,new_len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is a little scary -- if the new length is set but computing the new start fails, and the original iterator is still accessible, it will be truncated at the end rather than at the start. Let's update both fields after all errors have been checked.
Ditto in next().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Good point. Although__setstate__ is only supposed to be called for just created object when unpickle or make a deep copy, so there are no references to that iterator yet.
But there were other issue here.state could be a borrowed reference tor->len. It is used in two places: withPyNumber_Subtract() and withPyNumber_Multiply(). The second time it is used after setting the newr->state, when it can refer to a freed memory.
next() does not have such issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Seems that it never happens in normal code. You have to call__setstate__() manually with the out-of-range value.
gvanrossum left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
You may or may not want to change one thing, but if you do, no need to ask for a new review.
| PyObject*tmp=r->start; | ||
| r->start=new_start; | ||
| Py_SETREF(r->len,new_len); | ||
| Py_DECREF(tmp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I don't see a scenario where we can't just use
Py_SETREF(r->len, new_len);Py_SETREF(r->start, new_start);(which would be a little easier to follow).
Bothnew_len andnew_start are definitely new references we own, so even ifstate was a borrowed reference tor->len everything would be all right.
I'll leave it up to you though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Py_SETREF can only help when you assign a single object attribute, or if the attributes are independent. Two sequentialPy_SETREFs can be a sign of a bug.
We do not check the type ofstate. It can be an arbitrary Python object with methods__lt__,__gt__,__mul__ and__rsub__. Therefore we do not control the types ofnew_len andnew_start. Therefore we do not control the types ofr->len andr->start. They can have__del__ methods which release the GIL after assignment inPy_SETREF. When the GIL is released, the iterator object can be used in other thread when it is in inconsistent state -- newr->len and oldr->start.
It never occurs in normal code (state is always an exact int), but if you try hard, you perhaps can reproduce this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Aha, that's a scenario I hadn't considered. Maybe the next time I am asked in some kind of Q&A or interview "do you have any regrets" I should mention__del__ methods.
* main: (112 commits)pythongh-99894: Ensure the local names don't collide with the test file in traceback suggestion error checking (python#99895)pythongh-99612: Fix PyUnicode_DecodeUTF8Stateful() for ASCII-only data (pythonGH-99613) Doc: Add summary line to isolation_level & autocommit sqlite3.connect params (python#99917)pythonGH-98906 ```re``` module: ```search() vs. match()``` section should mention ```fullmatch()``` (pythonGH-98916)pythongh-89189: More compact range iterator (pythonGH-27986) bpo-47220: Document the optional callback parameter of weakref.WeakMethod (pythonGH-25491)pythonGH-99905: Fix output of misses in summarize_stats.py execution counts (pythonGH-99906)pythongh-99845: PEP 670: Convert PyObject macros to functions (python#99850)pythongh-99845: Use size_t type in __sizeof__() methods (python#99846)pythonGH-99877) Fix typo in exception message in `multiprocessing.pool` (python#99900)pythongh-87092: move all localsplus preparation into separate function called from assembler stage (pythonGH-99869)pythongh-99891: Fix infinite recursion in the tokenizer when showing warnings (pythonGH-99893)pythongh-99824: Document that sqlite3.connect implicitly open a transaction if autocommit=False (python#99825)pythonGH-81057: remove static state from suggestions.c (python#99411) Improve zip64 limit error message (python#95892)pythongh-98253: Break potential reference cycles in external code worsened by typing.py lru_cache (python#98591)pythongh-99127: Allow some features of syslog to the main interpreter only (pythongh-99128)pythongh-82836: fix private network check (python#97733) Docs: improve accuracy of socketserver reference (python#24767) ...
Uh oh!
There was an error while loading.Please reload this page.