Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
2f79c014
Commit
2f79c014
authored
Feb 03, 2018
by
Bar Harel
Committed by
Yury Selivanov
Feb 02, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-32734: Fix asyncio.Lock multiple acquire safety issue (GH-5466)
parent
66771422
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
75 additions
and
10 deletions
+75
-10
Lib/asyncio/locks.py
Lib/asyncio/locks.py
+22
-10
Lib/test/test_asyncio/test_locks.py
Lib/test/test_asyncio/test_locks.py
+50
-0
Misc/ACKS
Misc/ACKS
+1
-0
Misc/NEWS.d/next/Library/2018-02-01-01-34-47.bpo-32734.gCV9AD.rst
...S.d/next/Library/2018-02-01-01-34-47.bpo-32734.gCV9AD.rst
+2
-0
No files found.
Lib/asyncio/locks.py
View file @
2f79c014
...
...
@@ -183,16 +183,22 @@ class Lock(_ContextManagerMixin):
fut
=
self
.
_loop
.
create_future
()
self
.
_waiters
.
append
(
fut
)
# Finally block should be called before the CancelledError
# handling as we don't want CancelledError to call
# _wake_up_first() and attempt to wake up itself.
try
:
await
fut
self
.
_locked
=
True
return
True
try
:
await
fut
finally
:
self
.
_waiters
.
remove
(
fut
)
except
futures
.
CancelledError
:
if
not
self
.
_locked
:
self
.
_wake_up_first
()
raise
finally
:
self
.
_waiters
.
remove
(
fut
)
self
.
_locked
=
True
return
True
def
release
(
self
):
"""Release a lock.
...
...
@@ -212,11 +218,17 @@ class Lock(_ContextManagerMixin):
raise
RuntimeError
(
'Lock is not acquired.'
)
def
_wake_up_first
(
self
):
"""Wake up the first waiter who isn't cancelled."""
for
fut
in
self
.
_waiters
:
if
not
fut
.
done
():
fut
.
set_result
(
True
)
break
"""Wake up the first waiter if it isn't done."""
try
:
fut
=
next
(
iter
(
self
.
_waiters
))
except
StopIteration
:
return
# .done() necessarily means that a waiter will wake up later on and
# either take the lock, or, if it was cancelled and lock wasn't
# taken already, will hit this again and wake up a new waiter.
if
not
fut
.
done
():
fut
.
set_result
(
True
)
class
Event
:
...
...
Lib/test/test_asyncio/test_locks.py
View file @
2f79c014
...
...
@@ -200,6 +200,56 @@ class LockTests(test_utils.TestCase):
self
.
assertTrue
(
tb
.
cancelled
())
self
.
assertTrue
(
tc
.
done
())
def
test_cancel_release_race
(
self
):
# Issue 32734
# Acquire 4 locks, cancel second, release first
# and 2 locks are taken at once.
lock
=
asyncio
.
Lock
(
loop
=
self
.
loop
)
lock_count
=
0
call_count
=
0
async
def
lockit
():
nonlocal
lock_count
nonlocal
call_count
call_count
+=
1
await
lock
.
acquire
()
lock_count
+=
1
async
def
lockandtrigger
():
await
lock
.
acquire
()
self
.
loop
.
call_soon
(
trigger
)
def
trigger
():
t1
.
cancel
()
lock
.
release
()
t0
=
self
.
loop
.
create_task
(
lockandtrigger
())
t1
=
self
.
loop
.
create_task
(
lockit
())
t2
=
self
.
loop
.
create_task
(
lockit
())
t3
=
self
.
loop
.
create_task
(
lockit
())
# First loop acquires all
test_utils
.
run_briefly
(
self
.
loop
)
self
.
assertTrue
(
t0
.
done
())
# Second loop calls trigger
test_utils
.
run_briefly
(
self
.
loop
)
# Third loop calls cancellation
test_utils
.
run_briefly
(
self
.
loop
)
# Make sure only one lock was taken
self
.
assertEqual
(
lock_count
,
1
)
# While 3 calls were made to lockit()
self
.
assertEqual
(
call_count
,
3
)
self
.
assertTrue
(
t1
.
cancelled
()
and
t2
.
done
())
# Cleanup the task that is stuck on acquire.
t3
.
cancel
()
test_utils
.
run_briefly
(
self
.
loop
)
self
.
assertTrue
(
t3
.
cancelled
())
def
test_finished_waiter_cancelled
(
self
):
lock
=
asyncio
.
Lock
(
loop
=
self
.
loop
)
...
...
Misc/ACKS
View file @
2f79c014
...
...
@@ -602,6 +602,7 @@ Milton L. Hankins
Stephen Hansen
Barry Hantman
Lynda Hardman
Bar Harel
Derek Harland
Jason Harper
David Harrigan
...
...
Misc/NEWS.d/next/Library/2018-02-01-01-34-47.bpo-32734.gCV9AD.rst
0 → 100644
View file @
2f79c014
Fixed ``asyncio.Lock()`` safety issue which allowed acquiring and locking
the same lock multiple times, without it being free. Patch by Bar Harel.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment