Skip to content

Conversation

thp
Copy link
Contributor

@thp thp commented Mar 27, 2019

Using: Python 3.8 (git commit ID: d5a5a33), the following code snippet:

a = {0: 0}

for i in a:
    del a[i]
    a[i+1] = 0
    print(i)

Prints the following output:

0
1
2
3
4

The reason for this seems to be the way the internal key list is managed and the "next" value in this list is retrieved. The amount of items seems to be related to USABLE_FRACTION(PyDict_MINSIZE).

Since cases where the dictionary size changes are detected with a RuntimeError, I would expect the invariant "the number of iterations is the len() of the dict at the time the iterator is created" to be enforced. Whether to raise a StopIteration instead or raising a RuntimeError is up for debate.

This pull request tries to detect this corner case and raise a RuntimeError instead (plus a unit test).

Note also that without the patch, the __length_hint__() of the iterator actually underflows:

a = {0: 0}
it = iter(a)
print('Length hint:', it.__length_hint__())
next(it)
print('Length hint:', it.__length_hint__())
del a[0]
a[1] = 0
next(it)
print('Length hint:', it.__length_hint__())

Which - on an AMD64 machine - prints:

Length hint: 1
Length hint: 0
Length hint: 18446744073709551615

https://bugs.python.org/issue36452

@the-knights-who-say-ni
Copy link

Hello, and thanks for your contribution!

I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA).

Unfortunately we couldn't find an account corresponding to your GitHub username on bugs.python.org (b.p.o) to verify you have signed the CLA (this might be simply due to a missing "GitHub Name" entry in your b.p.o account settings). This is necessary for legal reasons before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue.

You can check yourself to see if the CLA has been received.

Thanks again for your contribution, we look forward to reviewing it!

@methane methane changed the title bpo-36452: dictiterobject: Track maximum iteration count via di->len bpo-36452: dictiter: track maximum iteration count Mar 28, 2019
@methane methane merged commit 796cc6e into python:master Mar 28, 2019
@thp thp deleted the sequential-dict-change-bug branch March 29, 2019 14:47
hroncok added a commit to hroncok/ansible that referenced this pull request May 22, 2019
With Python 3.8.0a4+, we get the following RuntimeError in Fedora:

PYTHONPATH=../../lib ../bin/dump_keywords.py --template-dir=../templates --output-dir=rst/reference_appendices/ -d ./keyword_desc.yml
Traceback (most recent call last):
  File "../bin/dump_keywords.py", line 49, in <module>
    for a in oblist[name]:
RuntimeError: dictionary keys changed during iteration

And:

    def populate(self):
        super(Interfaces, self).populate()
        self.facts['all_ipv4_addresses'] = list()
        self.facts['all_ipv6_addresses'] = list()

        data = self.responses[0]
        interfaces = self.parse_interfaces(data)

>       for key in interfaces.keys():
E       RuntimeError: dictionary keys changed during iteration

In TestDellos9Facts.test_dellos9_facts_gather_subset_default
and TestDellos9Facts.test_dellos9_facts_gather_subset_interfaces.

Python change: python/cpython#12596

Downstream bug: https://bugzilla.redhat.com/show_bug.cgi?id=1712531
jarrodmillman added a commit to jarrodmillman/networkx that referenced this pull request Aug 27, 2019
Python 3.8 tracks if any key names change while iterating.
python/cpython#12596
jarrodmillman added a commit to networkx/networkx that referenced this pull request Aug 27, 2019
Python 3.8 tracks if any key names change while iterating.
python/cpython#12596
jillr added a commit to jillr/ansible that referenced this pull request Dec 4, 2019
Python now throws a RuntimeError if dict keys are modified mid-iteration.
python/cpython#12596
Cast filter dicts to list before iteration.

Fixes: 65024
Related: 65434
MridulS pushed a commit to MridulS/networkx that referenced this pull request Feb 4, 2023
Python 3.8 tracks if any key names change while iterating.
python/cpython#12596
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants