diff options
author | Thomas Grainger <tagrain@gmail.com> | 2021-08-28 17:07:37 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-28 17:07:37 (GMT) |
commit | 206b21ed9f64fedff67bfea7cf73e423e3e32393 (patch) | |
tree | e9ee661a2ba04688ed086cd5b5f79cfdc9af8ff4 /Lib/_weakrefset.py | |
parent | 28db1f61f20352c02e4ae1518e5aeb6505df3045 (diff) | |
download | cpython-206b21ed9f64fedff67bfea7cf73e423e3e32393.zip cpython-206b21ed9f64fedff67bfea7cf73e423e3e32393.tar.gz cpython-206b21ed9f64fedff67bfea7cf73e423e3e32393.tar.bz2 |
bpo-44962: Fix a race in WeakKeyDict, WeakValueDict and WeakSet when two threads attempt to commit the last pending removal (GH-27921)
Fixes:
Traceback (most recent call last):
File "/home/graingert/projects/asyncio-demo/demo.py", line 36, in <module>
sys.exit(main())
File "/home/graingert/projects/asyncio-demo/demo.py", line 30, in main
test_all_tasks_threading()
File "/home/graingert/projects/asyncio-demo/demo.py", line 24, in test_all_tasks_threading
results.append(f.result())
File "/usr/lib/python3.10/concurrent/futures/_base.py", line 438, in result
return self.__get_result()
File "/usr/lib/python3.10/concurrent/futures/_base.py", line 390, in __get_result
raise self._exception
File "/usr/lib/python3.10/concurrent/futures/thread.py", line 52, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/lib/python3.10/asyncio/runners.py", line 47, in run
_cancel_all_tasks(loop)
File "/usr/lib/python3.10/asyncio/runners.py", line 56, in _cancel_all_tasks
to_cancel = tasks.all_tasks(loop)
File "/usr/lib/python3.10/asyncio/tasks.py", line 53, in all_tasks
tasks = list(_all_tasks)
File "/usr/lib/python3.10/_weakrefset.py", line 60, in __iter__
with _IterationGuard(self):
File "/usr/lib/python3.10/_weakrefset.py", line 33, in __exit__
w._commit_removals()
File "/usr/lib/python3.10/_weakrefset.py", line 57, in _commit_removals
discard(l.pop())
IndexError: pop from empty list
Also fixes:
Exception ignored in: weakref callback <function WeakKeyDictionary.__init__.<locals>.remove at 0x00007fe82245d2e0>
Traceback (most recent call last):
File "/usr/lib/pypy3/lib-python/3/weakref.py", line 390, in remove
del self.data[k]
KeyError: <weakref at 0x00007fe76e8d8180; dead>
Exception ignored in: weakref callback <function WeakKeyDictionary.__init__.<locals>.remove at 0x00007fe82245d2e0>
Traceback (most recent call last):
File "/usr/lib/pypy3/lib-python/3/weakref.py", line 390, in remove
del self.data[k]
KeyError: <weakref at 0x00007fe76e8d81a0; dead>
Exception ignored in: weakref callback <function WeakKeyDictionary.__init__.<locals>.remove at 0x00007fe82245d2e0>
Traceback (most recent call last):
File "/usr/lib/pypy3/lib-python/3/weakref.py", line 390, in remove
del self.data[k]
KeyError: <weakref at 0x000056548f1e24a0; dead>
See: https://github.com/agronholm/anyio/issues/362#issuecomment-904424310
See also: https://bugs.python.org/issue29519
Co-authored-by: Ćukasz Langa <lukasz@langa.pl>
Diffstat (limited to 'Lib/_weakrefset.py')
-rw-r--r-- | Lib/_weakrefset.py | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py index b267780..2a27684 100644 --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -51,10 +51,14 @@ class WeakSet: self.update(data) def _commit_removals(self): - l = self._pending_removals + pop = self._pending_removals.pop discard = self.data.discard - while l: - discard(l.pop()) + while True: + try: + item = pop() + except IndexError: + return + discard(item) def __iter__(self): with _IterationGuard(self): |