Skip to content

Clear static types in Py_Finalize() for embedded Python #90575

Closed

Description

@vstinner
BPO 46417
Nosy @vstinner, @phsilva, @encukou, @corona10, @miss-islington, @shihai1991, @erlend-aasland, @kumaraditya303
PRs
  • bpo-46417: Finalize structseq types at exit #30645
  • bpo-46417: _testembed.c avoids Py_SetProgramName() #30732
  • bpo-46417: _thread module uses PyStructSequence_NewType() #30733
  • bpo-46417: time module uses PyStructSequence_NewType() #30734
  • bpo-46417: signal uses PyStructSequence_NewType() #30735
  • bpo-46417: _curses uses PyStructSequence_NewType() #30736
  • bpo-46417: Py_Finalize() clears static types #30743
  • bpo-46417: Call _PyDebug_PrintTotalRefs() later #30744
  • bpo-46417: Add missing types of _PyTypes_InitTypes() #30749
  • bpo-46417: Revert remove_subclass() change #30750
  • bpo-46417: Add _PyType_CAST() macro #30760
  • bpo-46417: Add _PyType_GetSubclasses() function #30761
  • bpo-46417: PyWeakref_GET_OBJECT() uses PyWeakref_CheckRef() #30763
  • bpo-46417: Use _PyType_CAST() in Objects directory #30764
  • bpo-46417: Use _PyType_CAST() in Python directory #30769
  • bpo-46417: Use _PyType_CAST() in Modules directory #30767
  • bpo-46417: Fix type recurse_down_subclasses() #30775
  • bpo-46417: Fix race condition on setting type __bases__ #30788
  • [3.10] bpo-46417: Fix race condition on setting type __bases__ (GH-30788) #30789
  • [3.9] bpo-46417: Fix race condition on setting type __bases__ (GH-30788) #30790
  • bpo-46417: Debug tp_subclasses crash #30791
  • bpo-46417: remove_subclass() clears tp_subclasses #30793
  • bpo-46417: Cleanup typeobject.c code #30795
  • bpo-46417: Clear more static types #30796
  • bpo-46417: _PyTypes_FiniTypes() clears object and type #30798
  • bpo-46417: Cleanup _PyExc_InitTypes() #30804
  • bpo-46417: Py_Finalize() clears static exceptioins #30805
  • bpo-46417: Clear Unicode static types at exit #30806
  • bpo-46417: Clear _io module static objects at exit #30807
  • bpo-46417: Clear symtable identifiers at exit #30809
  • bpo-46417: Fix _PyStaticType_Dealloc() #30810
  • bpo-46417: _PyList_Fini() clears indexerr #30815
  • bpo-46417: signal: move siginfo_type to the module state #30964
  • bpo-46417: _PyStructSequence_FiniType() updates _Py_RefTotal #30988
  • Files
  • cannot_deallocate.patch
  • cannot_deallocate2.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 = None
    closed_at = <Date 2022-01-27.20:22:54.970>
    created_at = <Date 2022-01-17.17:19:20.743>
    labels = ['interpreter-core', '3.11']
    title = 'Clear static types in Py_Finalize() for embedded Python'
    updated_at = <Date 2022-01-28.13:08:43.043>
    user = 'https://github.com/vstinner'

    bugs.python.org fields:

    activity = <Date 2022-01-28.13:08:43.043>
    actor = 'vstinner'
    assignee = 'none'
    closed = True
    closed_date = <Date 2022-01-27.20:22:54.970>
    closer = 'vstinner'
    components = ['Interpreter Core']
    creation = <Date 2022-01-17.17:19:20.743>
    creator = 'vstinner'
    dependencies = []
    files = ['50576', '50577']
    hgrepos = []
    issue_num = 46417
    keywords = ['patch']
    message_count = 50.0
    messages = ['410808', '410858', '410866', '411025', '411033', '411049', '411063', '411064', '411066', '411070', '411071', '411073', '411076', '411077', '411117', '411118', '411122', '411127', '411139', '411143', '411148', '411182', '411201', '411202', '411203', '411232', '411255', '411256', '411257', '411263', '411271', '411272', '411275', '411276', '411281', '411290', '411291', '411292', '411296', '411300', '411303', '411304', '411305', '411307', '411317', '411329', '411332', '411917', '411918', '411994']
    nosy_count = 8.0
    nosy_names = ['vstinner', 'phsilva', 'petr.viktorin', 'corona10', 'miss-islington', 'shihai1991', 'erlendaasland', 'kumaraditya']
    pr_nums = ['30645', '30732', '30733', '30734', '30735', '30736', '30743', '30744', '30749', '30750', '30760', '30761', '30763', '30764', '30769', '30767', '30775', '30788', '30789', '30790', '30791', '30793', '30795', '30796', '30798', '30804', '30805', '30806', '30807', '30809', '30810', '30815', '30964', '30988']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue46417'
    versions = ['Python 3.11']

    Activity

    1. vstinner commented on Jan 17, 2022

      @vstinner
      MemberAuthor

      Converting static types to heap types is a work-in-progress:

      • bpo-40077: "Convert static types to heap types: use PyType_FromSpec()"
      • At December 29, 2020, 43% (89/206) of types are declared as heap types on a total of 206 types. For comparison, in Python 3.8, only 9% (15/172) of types were declared as heap types: 74 types have been converted in the meanwhile.
      • https://vstinner.github.io/isolate-subinterpreters.html

      Static types are still causing issues with Py_Initialize() / Py_Finalize() is called multiple times in the same process, which is a supported use case for embedded Python. See bpo-45691 "Partial moving of core objects to interpreter state is incorrect at best, unsafe at worse" for a recent example with sys.float_info where sys.float_info.n_unnamed_fields holds a reference to a Python object.

      In june 2020, I wrote #64962 to clear static types at exit. But I abandoned my attempt because of bugs. Copy of my https://bugs.python.org/issue1635741#msg371119 message:

      """
      I wrote PR 20763 to "finalize" static types in Py_Finalize(). It mostly works, but "./Programs/_testembed test_forced_io_encoding" crash. This program calls Py_Initialize() and Py_Finalize() multiple times in a loop.

      It doesn't look to be safe to clear static types. Many functions rely on the fact that static types are "always there" and are never finalized. Also, only a few static types are cleared by my PR: many static types are left unchanged. For example, static types of the _io module.

      It seems like a safer approach is to continue the work on bpo-40077: "Convert static types to PyType_FromSpec()".
      """

      I propose a "best effort" approach: only clear a static type if it is no longer used. For example, check its reference count and its __subclasses__() method.

    2. encukou commented on Jan 18, 2022

      @encukou
      Member

      If we have static types, that means there is a mechanism to share some objects across interpreters.
      And if that's the case, why can't small ints (like sys.float_info.n_unnamed_fields) be static & shared as well?

    3. vstinner commented on Jan 18, 2022

      @vstinner
      MemberAuthor

      If we have static types, that means there is a mechanism to share some objects across interpreters.

      Sharing objects between interpreters is bad and is causing complex bugs. See a recent example of an object traveling from one interpreter to another and then causing a random crash on Windows related to the garbage collector:

      And if that's the case, why can't small ints (like sys.float_info.n_unnamed_fields) be static & shared as well?

      I would prefer to discuss that in other issues like bpo-40255 or bpo-39511, and focus this issue on fixing the static types implementation when Python is embedded in an application.

      --

      Hum, this issue is not really related to sub-interpreters. My proposed PR only changes Py_Finalize(): the main interpreter.

    4. changed the title [-][subinterpreters] Clear static types in Py_Finalize()[/-] [+]Clear static types in Py_Finalize() for embedded Python[/+] on Jan 18, 2022
    5. changed the title [-][subinterpreters] Clear static types in Py_Finalize()[/-] [+]Clear static types in Py_Finalize() for embedded Python[/+] on Jan 18, 2022
    6. encukou commented on Jan 20, 2022

      @encukou
      Member

      Sharing objects between interpreters is bad

      That's your opinion, I don't necessarily share it.

      and is causing complex bugs.

      But converting static things (types, small ints) to heap is also causing bugs :(

      ----

      Anyway, for this issue: is there a way to test if the types are correctly reinitialized if there are multiple finalize/init cycles?
      I worry about introducing more unexpected issues here.

    7. vstinner commented on Jan 20, 2022

      @vstinner
      MemberAuthor

      If tomorrow static types are shared between sub-interpreters, it doesn't solve this problem: we still need to release memory allocated by Py_Initialize() in Py_Finalize() when Python is embedded. This issue is a sub-set of the big bpo-1635741 which explains the rationale. Again, this issue is not about sub-interpreters.

      Anyway, for this issue: is there a way to test if the types are correctly reinitialized if there are multiple finalize/init cycles? I worry about introducing more unexpected issues here.

      I wasn't sure how to test it. But well, Dong-hee and you asked for tests, so I added tests for my PR ;-)

    8. 33 remaining items

    9. vstinner commented on Jan 22, 2022

      @vstinner
      MemberAuthor

      New changeset 9c8e490 by Victor Stinner in branch 'main':
      bpo-46417: Clear _io module static objects at exit (GH-30807)
      9c8e490

    10. vstinner commented on Jan 22, 2022

      @vstinner
      MemberAuthor

      New changeset 12f4ac3 by Victor Stinner in branch 'main':
      bpo-46417: Clear symtable identifiers at exit (GH-30809)
      12f4ac3

    11. vstinner commented on Jan 22, 2022

      @vstinner
      MemberAuthor

      New changeset a1444f4 by Victor Stinner in branch 'main':
      bpo-46417: Fix _PyStaticType_Dealloc() (GH-30810)
      a1444f4

    12. vstinner commented on Jan 22, 2022

      @vstinner
      MemberAuthor

      The _PyStaticType_Dealloc() function cannot call PyObject_ClearWeakRefs() if the refcount is not zero. I am not sure if it's a real issue or not. Maybe the weakref list must be cleared (release memory), but callbacks must not be called?

    13. vstinner commented on Jan 22, 2022

      @vstinner
      MemberAuthor

      cannot_deallocate2.patch: updated patch to debug which types are not cleared at exit.

    14. vstinner commented on Jan 22, 2022

      @vstinner
      MemberAuthor

      New changeset a1444f4 by Victor Stinner in branch 'main':
      bpo-46417: Fix _PyStaticType_Dealloc() (GH-30810)
      a1444f4

      At this commit, Py_Finalize() no longer leaks references. It exceeded my expectations, it even makes _Py_RefTotal negative :-D

          $ ./python -I -X showrefcount -c pass
          [-4 refs, 61 blocks]

      I'm not sure why it's negative, but bpo-46449 should be investigate first.

    15. vstinner commented on Jan 23, 2022

      @vstinner
      MemberAuthor

      See also bpo-46476: Not all memory allocated by _Py_Quicken() is released at Python exit.

    16. vstinner commented on Jan 23, 2022

      @vstinner
      MemberAuthor

      New changeset 976dec9 by Victor Stinner in branch 'main':
      bpo-46417: _PyList_Fini() clears indexerr (GH-30815)
      976dec9

    17. vstinner commented on Jan 23, 2022

      @vstinner
      MemberAuthor

      See also bpo-46476: Not all memory allocated by _Py_Quicken() is released at Python exit.

      If you apply my workaround for bpo-46476:
      https://bugs.python.org/issue46476#msg411321

      Python no longer leaks any memory block at exit for the simplest command!

      $ ./python -I -X showrefcount -c pass
      [-5 refs, 0 blocks]

      Moreover, I modified deepfreeze to only freeze importlib._bootstrap and importlib._bootstrap_external. It confirms that bpo-46449 is causing the negative reference count, because with these additional local changes I get a positive _Py_RefTotal:

      $ ./python -I -X showrefcount -c pass
      [6 refs, 0 blocks]
    18. vstinner commented on Jan 27, 2022

      @vstinner
      MemberAuthor

      New changeset 6c6a153 by Victor Stinner in branch 'main':
      bpo-46417: signal: move siginfo_type to the module state (GH-30964)
      6c6a153

    19. vstinner commented on Jan 27, 2022

      @vstinner
      MemberAuthor

      I close the issue. I cleared most static types at exit. Following work can be done in bpo-40077 or other issues.

    20. vstinner commented on Jan 28, 2022

      @vstinner
      MemberAuthor

      New changeset 9a24127 by Victor Stinner in branch 'main':
      bpo-46417: _PyStructSequence_FiniType() updates _Py_RefTotal (GH-30988)
      9a24127

    21. transferred this issue fromon Apr 10, 2022
    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

      3.11only security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions