Skip to content
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

coroutine wrapper reentrancy #68530

Closed
1st1 opened this issue Jun 1, 2015 · 10 comments
Closed

coroutine wrapper reentrancy #68530

1st1 opened this issue Jun 1, 2015 · 10 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error

Comments

@1st1
Copy link
Member

1st1 commented Jun 1, 2015

BPO 24342
Nosy @gvanrossum, @smontanaro, @ncoghlan, @vstinner, @ericsnowcurrently, @1st1
Files
  • coro_wrapper.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/1st1'
    closed_at = <Date 2015-06-02.22:47:26.214>
    created_at = <Date 2015-06-01.02:11:34.369>
    labels = ['interpreter-core', 'type-bug']
    title = 'coroutine wrapper reentrancy'
    updated_at = <Date 2015-06-03.02:31:01.674>
    user = 'https://github.com/1st1'

    bugs.python.org fields:

    activity = <Date 2015-06-03.02:31:01.674>
    actor = 'python-dev'
    assignee = 'yselivanov'
    closed = True
    closed_date = <Date 2015-06-02.22:47:26.214>
    closer = 'yselivanov'
    components = ['Interpreter Core']
    creation = <Date 2015-06-01.02:11:34.369>
    creator = 'yselivanov'
    dependencies = []
    files = ['39578']
    hgrepos = []
    issue_num = 24342
    keywords = ['patch']
    message_count = 10.0
    messages = ['244569', '244577', '244585', '244593', '244594', '244595', '244621', '244635', '244706', '244724']
    nosy_count = 8.0
    nosy_names = ['gvanrossum', 'skip.montanaro', 'ncoghlan', 'vstinner', 'Arfrever', 'python-dev', 'eric.snow', 'yselivanov']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue24342'
    versions = ['Python 3.5', 'Python 3.6']

    @1st1
    Copy link
    Member Author

    1st1 commented Jun 1, 2015

    Consider following piece of code:

        async def foo():
            return 'spam'
    
        def wrapper(coro):
            async def wrap(coro):
                print('before')
                try:
                    return await coro
                finally:
                    print('after')
            return wrap(coro)
    
        import sys
        sys.set_coroutine_wrapper(wrapper)
        print(foo().send(None))

    Current python will crash with a "RuntimeError: maximum recursion depth exceeded", because "wrap" is itself a coroutine, so ceval will call "wrapper" recursively.

    There are three options here:

    1. Leave things as is;

    2. Add a flag in tstate that coroutine_wrapper is executing, and raise a RuntimeError if it's reentering;

    3. Add a flag in tstate (see 2) and skip wrapping when reentering (i.e. return what was passed to the wrapper).

    The attached patch implements (2). It also makes PyEval*CoroWrapper methods private.

    I, myself, vote for option 2.

    @1st1 1st1 self-assigned this Jun 1, 2015
    @1st1 1st1 added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Jun 1, 2015
    @1st1 1st1 changed the title coroutine wrapper recursion coroutine wrapper reentrancy Jun 1, 2015
    @1st1 1st1 added the type-bug An unexpected behavior, bug, or error label Jun 1, 2015
    @smontanaro
    Copy link
    Contributor

    On Sun, May 31, 2015 at 9:11 PM, Yury Selivanov <report@bugs.python.org> wrote:

    Current python will crash with a "RuntimeError: maximum recursion depth exceeded" ...

    If it's good enough for other programmer-induced infinite recursion
    (and in my experience the cause is generally quite obvious from the
    traceback), why wouldn't it be good enough in this case?

    @smontanaro smontanaro changed the title coroutine wrapper reentrancy coroutine wrapper recursion Jun 1, 2015
    @ericsnowcurrently
    Copy link
    Member

    Changing the title back. :)

    @ericsnowcurrently ericsnowcurrently changed the title coroutine wrapper recursion coroutine wrapper reentrancy Jun 1, 2015
    @1st1
    Copy link
    Member Author

    1st1 commented Jun 1, 2015

    why wouldn't it be good enough in this case?

    Because it's highly non-obvious, it took me a while to understand what's *actually* going on.

    @smontanaro
    Copy link
    Contributor

    This is a bit off topic, but why did my reply to Yuri's ticket by email change the title? I didn't mess with the subject in my mail.

    @ericsnowcurrently
    Copy link
    Member

    @Skip, because roundup will change the title to the subject of the email and the title had been changed after the message to which you replied.

    @ncoghlan
    Copy link
    Contributor

    ncoghlan commented Jun 2, 2015

    Making sure I'm following the issue correctly here:

    1. wrapper is a normal function, so there's no change for set_couroutine_wrapper() to detect anything might be amiss

    2. any "async def" statement will call the registered coroutine wrapper to wrap the created function and turn it into a coroutine

    3. this means any coroutine wrapper that directly or indirectly includes an "async def" statement will fail with RecursionError, without the problem being at all obvious

    4. Yury's proposed patch effectively detects the use of "async def" inside a coroutine wrapper definition

    I like the idea in principle, I don't like the error message in the current patch (since it only makes sense if you already understand the chain of reasoning above).

    While it's a little verbose, I suggest an error like: "Coroutine wrapper %r attempted to recursively wrap %r", passing in the currently registered coroutine wrapper, and the code object we're attempting to wrap, respectively.

    The latter repr gives the name, filename and line number of the offending code object, while the former should give the qualname of the registered wrapper.

    The docs for set_coroutine_wrapper() should also be tweaked to note the constraint that the wrapper function cannot itself define new asynchronous functions (neither directly nor indirectly).

    @1st1
    Copy link
    Member Author

    1st1 commented Jun 2, 2015

    Thanks, Nick! I'll commit the patch with your error message (it's much better!)

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jun 2, 2015

    New changeset 19d613c2cd5f by Yury Selivanov in branch '3.5':
    bpo-24342: Let wrapper set by sys.set_coroutine_wrapper fail gracefully
    https://hg.python.org/cpython/rev/19d613c2cd5f

    New changeset 8a6db1679a23 by Yury Selivanov in branch 'default':
    bpo-24342: Let wrapper set by sys.set_coroutine_wrapper fail gracefully
    https://hg.python.org/cpython/rev/8a6db1679a23

    @1st1 1st1 closed this as completed Jun 2, 2015
    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jun 3, 2015

    New changeset d11cb1218489 by Yury Selivanov in branch '3.5':
    bpo-24342: No need to use PyAPI_FUNC for _PyEval_ApplyCoroutineWrapper
    https://hg.python.org/cpython/rev/d11cb1218489

    New changeset b83fbc13ae1e by Yury Selivanov in branch 'default':
    bpo-24342: No need to use PyAPI_FUNC for _PyEval_ApplyCoroutineWrapper
    https://hg.python.org/cpython/rev/b83fbc13ae1e

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    4 participants