FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Disallow multiple initializations of asyncio tasks and futures · Issue #142615 · python/cpython · GitHub

Repository navigation

Disallow multiple initializations of asyncio tasks and futures #142615

Description

Problem

This is a long standing issue of the _asyncio accelerator module where _asyncio.Task and _asyncio.Future define tp_init slot instead of tp_new slot for creating the object. This allows malicious code to re-initialize objects while tasks and futures are executing which can crash the interpreter because internally the fields of tasks and futures are accessed using borrowed references for performance.

There have been multiple reports of this where we previously changed the code to use strong references like #126080 but still there are a lot of places where borrowed references to loop is used etc.

IMO changing the code to use strong references is not the solution here, instead we should make tasks and futures immutable at C level so that this issue would not exist in the first place. Avoiding strong references is also important for performance especially in free-threading.

Proposal

Historically _asyncio.Task and _asyncio.Future define tp_init rather than tp_new, so we cannot change it to use tp_new as it would break compatibility with subclasses. To preserve backward compatibility I propose to to instead allow tp_init to be called exactly once and if user tries to initialize it again, raise RuntimeError that task cannot be re-initialized. This would prevent all these issues while preserving backwards compatibility and performance.

Linked PRs

Activity

  1. gvanrossum commented on Dec 12, 2025

    Member

    I'm a little surprised that we can't change __init__ to __new__, but I trust there's working code that we want to support that relies on it -- somehow. (But would that code perhaps also be broken when we disallow a second __init__ call?)

    Just make sure to make the same change in the pure Python code.

    And I would love to see an example in the wild that would break by switching to __new__.

  2. kumaraditya303 commented on Dec 12, 2025

    ContributorAuthor

    I'm a little surprised that we can't change init to new, but I trust there's working code that we want to support that relies on it -- somehow. (But would that code perhaps also be broken when we disallow a second init call?)

    I did a similar change of changing __init__ to __new__ for struct.Struct a while ago in #78724 but it had to reverted because it broke third party code.

  3. gvanrossum commented on Dec 12, 2025

    Member

    Bummer. I wonder what people are doing in the wild. For struct.Struct, the only clue in that issue is this:

    reverted, since it broke code for users in the wild who were subclassing struct.Struct.

    And reading through the reverted PR, I find #94532 (comment) which shows the problem. (IIUC, the added builtin __new__ doesn't support all possible signatures, which means subclasses would have to override __new__ to match their __init__ and it should call something like super().__new__(format).

    Okay, so I agree we probably shouldn't change. Sigh. I presume we have this problem with all classes that define both __new__ and __init__.

  4. added a commit that references this issue on Jan 3, 2026
  5. kumaraditya303 commented on Jan 3, 2026

    ContributorAuthor

    The PR is merged and multiple initializations of asyncio tasks and futures is disallowed now in both pure python and C implementation.

  6. moved this from Todo to Done in asyncioon Jan 3, 2026
  7. added a commit that references this issue on Feb 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL