-
-
Notifications
You must be signed in to change notification settings - Fork 33.6k
bpo-44962 fix a race in WeakKeyDict, WeakValueDict and WeakSet when two threads attempt to commit the last pending removal #27921
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 all commits
5a0dc76
3f74f24
08f31cb
738dc9a
f3585ef
6476722
36fd3f0
54a0032
aada0e4
b2b25d0
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 |
|---|---|---|
|
|
@@ -119,14 +119,17 @@ def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref): | |
| self.data = {} | ||
| self.update(other, **kw) | ||
|
|
||
| def _commit_removals(self): | ||
| l = self._pending_removals | ||
| def _commit_removals(self, _atomic_removal=_remove_dead_weakref): | ||
| pop = self._pending_removals.pop | ||
graingert marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| d = self.data | ||
| # We shouldn't encounter any KeyError, because this method should | ||
| # always be called *before* mutating the dict. | ||
| while l: | ||
| key = l.pop() | ||
| _remove_dead_weakref(d, key) | ||
| while True: | ||
| try: | ||
| key = pop() | ||
| except IndexError: | ||
| return | ||
| _atomic_removal(d, key) | ||
|
|
||
| def __getitem__(self, key): | ||
| if self._pending_removals: | ||
|
|
@@ -370,7 +373,10 @@ def remove(k, selfref=ref(self)): | |
| if self._iterating: | ||
| self._pending_removals.append(k) | ||
| else: | ||
| del self.data[k] | ||
| try: | ||
| del self.data[k] | ||
| except KeyError: | ||
| pass | ||
| self._remove = remove | ||
| # A list of dead weakrefs (keys to be removed) | ||
| self._pending_removals = [] | ||
|
|
@@ -384,11 +390,16 @@ def _commit_removals(self): | |
| # because a dead weakref never compares equal to a live weakref, | ||
| # even if they happened to refer to equal objects. | ||
| # However, it means keys may already have been removed. | ||
| l = self._pending_removals | ||
| pop = self._pending_removals.pop | ||
| d = self.data | ||
| while l: | ||
| while True: | ||
| try: | ||
| key = pop() | ||
| except IndexError: | ||
| return | ||
|
|
||
| try: | ||
| del d[l.pop()] | ||
| del d[key] | ||
| except KeyError: | ||
| pass | ||
|
Comment on lines
403
to
404
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. Observation: it kind of weirded me out there has to be a Well, after some digging I found this isn't about duplicates. This is about a race where one In fact, while There's some relevant info in https://bugs.python.org/issue21173 and https://bugs.python.org/issue28427. |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Fix a race in WeakKeyDictionary, WeakValueDictionary and WeakSet when two threads attempt to commit the last pending removal. This fixes asyncio.create_task and fixes a data loss in asyncio.run where shutdown_asyncgens is not run |
Uh oh!
There was an error while loading. Please reload this page.