[proxy] web.archive.org← back | site home | direct (HTTPS) ↗ | proxy home | ◑ dark◐ light
/ cpython Public
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

bpo-34872: Fix self-cancellation in C implementation of asyncio.Task #9679

Merged
merged 1 commit into from Oct 3, 2018

Conversation

Copy link
Contributor

elprans commented Oct 2, 2018

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

async def task1():
    async def task2():
        await task3     # task3 is never cancelled

    asyncio.current_task().cancel()
    await asyncio.create_task(task2())

The actuall error is a hardcoded call to future_cancel() instead of
calling the cancel() method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.

https://bugs.python.org/issue34872

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

    async def task1():
        async def task2():
            await task3     # task3 is never cancelled

        asyncio.current_task().cancel()
        await asyncio.create_task(task2())

The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.
1st1 approved these changes Oct 2, 2018
@@ -2713,14 +2713,19 @@ task_step_impl(TaskObj *task, PyObject *exc)

if (task->task_must_cancel) {
PyObject *r;
r = future_cancel(fut);
int is_true;
r = _PyObject_CallMethodId(fut, &PyId_cancel, NULL);
Copy link
Contributor

asvetlov Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is correct.
But I'd like to go one step forward: use Future_CheckExact and Task_CheckExact to call future_cancel() and _asyncio_Task_cancel_impl() as fast paths.

Copy link
Member

1st1 Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Id keep it as simple as possible as it needs to be backported to 3.6 & 3.7. A proper refactoring for C code is needed anyways, and I'll add this optimization.

Copy link
Contributor

asvetlov Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

1st1 merged commit 0c797a6 into python:master Oct 3, 2018
Copy link
Contributor

miss-islington commented Oct 3, 2018

Thanks @elprans for the PR, and @1st1 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.6, 3.7.
🐍🍒🤖

Copy link
Contributor

miss-islington commented Oct 3, 2018

Sorry, @elprans and @1st1, I could not cleanly backport this to 3.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 0c797a6aca1c293e530e18c5e9fa02c670a9a4ed 3.7

Copy link
Contributor

miss-islington commented Oct 3, 2018

Sorry, @elprans and @1st1, I could not cleanly backport this to 3.6 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 0c797a6aca1c293e530e18c5e9fa02c670a9a4ed 3.6

Copy link
Member

1st1 commented Oct 3, 2018

@elprans please submit two PRs to backport the change to 3.7 and 3.6. The automatic cherry-picking has failed :(

Copy link

bedevere-bot commented Oct 3, 2018

GH-9690 is a backport of this pull request to the 3.6 branch.

elprans added a commit to elprans/cpython that referenced this pull request Oct 3, 2018
….Task (pythonGH-9679)

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

    async def task1():
        async def task2():
            await task3     # task3 is never cancelled

        asyncio.current_task().cancel()
        await asyncio.create_task(task2())

The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.

(cherry picked from commit 548ce9d)
Copy link

bedevere-bot commented Oct 3, 2018

GH-9691 is a backport of this pull request to the 3.7 branch.

elprans added a commit to elprans/cpython that referenced this pull request Oct 3, 2018
….Task (pythonGH-9679)

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

    async def task1():
        async def task2():
            await task3     # task3 is never cancelled

        asyncio.current_task().cancel()
        await asyncio.create_task(task2())

The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario..
(cherry picked from commit 548ce9d)

Co-authored-by: Elvis Pranskevichus <elvis@magic.io>
miss-islington pushed a commit that referenced this pull request Oct 3, 2018
….Task (GH-9679) (GH-9690)

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

    async def task1():
        async def task2():
            await task3     # task3 is never cancelled

        asyncio.current_task().cancel()
        await asyncio.create_task(task2())

The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.

(cherry picked from commit 548ce9d)


https://bugs.python.org/issue34872
miss-islington pushed a commit that referenced this pull request Oct 3, 2018
….Task (GH-9679) (GH-9691)

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

    async def task1():
        async def task2():
            await task3     # task3 is never cancelled

        asyncio.current_task().cancel()
        await asyncio.create_task(task2())

The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario..
(cherry picked from commit 548ce9d)

Co-authored-by: Elvis Pranskevichus <elvis@magic.io>


https://bugs.python.org/issue34872
yahya-abou-imran pushed a commit to yahya-abou-imran/cpython that referenced this pull request Nov 2, 2018
…ythonGH-9679)

The C implementation of asyncio.Task currently fails to perform the
cancellation cleanup correctly in the following scenario.

    async def task1():
        async def task2():
            await task3     # task3 is never cancelled

        asyncio.current_task().cancel()
        await asyncio.create_task(task2())

The actuall error is a hardcoded call to `future_cancel()` instead of
calling the `cancel()` method of a future-like object.

Thanks to Vladimir Matveev for noticing the code discrepancy and to
Yury Selivanov for coming up with a pathological scenario.
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.

None yet

6 participants