GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-113190: Reenable non-debug interned string cleanup by eduardo-elizondo · Pull Request #113601 · python/cpython

Conversation

@eduardo-elizondo

@eduardo-elizondo eduardo-elizondo commented Dec 31, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

In GH-19474 we introduced immortalized interned strings. However, at the time, we didn't have a strict guarantee that a runtime shutdown (i.e Py_Finalize()) would completely cleanup all the allocated PyObjects (i.e a simple example of ./python -X showrefcount -c 'import itertools' would show leaks).

Today, these leaks have been largely fixed and there have been stricter guarantees into how obmalloc and the interpreter state works after a runtime shutdown. Given this, it should be safe to re-enable the interned string cleanup and revert the structseq test that had issues with this leaks before. This test should show the correctness of this code now.

  • Issue: python3.12 introduces numerous memory leaks (as reported by ASAN) #113190
  • Issue: Memory leak on executables embedded with 3.13 #113055

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

davidmerwin and tkieft reacted with heart emoji erlend-aasland and furkanonder reacted with rocket emoji
All reactions
  • ❤️ 2 reactions
  • 🚀 2 reactions
@eduardo-elizondo
Reenable non-debug interned string cleanup through _PyUnicode_ClearIn…
666ca33
…terned
@bedevere-app bedevere-app Bot added the awaiting review label Dec 31, 2023
@bedevere-app bedevere-app Bot mentioned this pull request Dec 31, 2023
python3.12 introduces numerous memory leaks (as reported by ASAN) #113190
Closed
@eduardo-elizondo
Revert test changes due to previously leftover leaks
23d1aff
@Eclips4 Eclips4 changed the title [DONOTMETGE] gh-113190: Reenable non-debug interned string cleanup [DO NOT MERGE] gh-113190: Reenable non-debug interned string cleanup Dec 31, 2023
@Eclips4 Eclips4 added the DO-NOT-MERGE label Dec 31, 2023
@Eclips4

Eclips4 commented Dec 31, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

I added DO-NOT-MERGE label for you :)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Eclips4 Eclips4 changed the title [DO NOT MERGE] gh-113190: Reenable non-debug interned string cleanup gh-113190: Reenable non-debug interned string cleanup Dec 31, 2023
@eduardo-elizondo

eduardo-elizondo commented Dec 31, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

I added DO-NOT-MERGE label for you :)

Thanks!! Will ping you once all the tests are passing to move this into safe-to-merge mode 🙂

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eduardo-elizondo

eduardo-elizondo commented Dec 31, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

@Eclips4 tests are passing! Could you help me by adding the "skip news" label (since it's probably not required) and removing the "DO-NOT-MERGE" label?

Thanks!!

Eclips4 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eduardo-elizondo eduardo-elizondo mentioned this pull request Dec 31, 2023
Memory leak on executables embedded with 3.13 #113055
Closed
@Eclips4 Eclips4 added skip news interpreter-core (Objects, Python, Grammar, and Parser dirs) needs backport to 3.12 only security fixes and removed DO-NOT-MERGE labels Dec 31, 2023
@eduardo-elizondo

eduardo-elizondo commented Jan 4, 2024

Copy link
Copy Markdown
Contributor Author

cc @nascheme to take a look when you have a chance!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nascheme

nascheme commented Jan 4, 2024

Copy link
Copy Markdown
Member

It would be nice to do a better cleanup but I'm concerned about how safe this actually is. Since we don't have an accurate refcnt for these strings, we are assuming that no one is actually still using them. It seems possible that some extensions or programs embedding Python could hang on to interned strings after Py_Finalize(). That would risk introducing "use-after-free" bugs. In the worst case, that could turn into an arbitrary code execution security bug.

Maybe I'm being too paranoid? I don't know how we could actually fix this though. Keeping hold of and using memory allocated by the Python runtime after Py_Finalize() surely puts you an very shaky ground. Previously, the obmalloc state was global to the process and you could keep using memory allocated from there after finalizing. With sub-interpeters potentially having their own obmalloc state, that's likely not okay.

My gut feeling is we should proceed cautiously, even though we would like to fix the leak. Maybe we could enable this for alphas and then turn it off again for release? Maybe we need to wait until we get python -X showrefcount showing zero for all or nearly all built-in and well known extensions? Seems like a tall order though.

eduardo-elizondo reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eduardo-elizondo

eduardo-elizondo commented Jan 5, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

@nascheme I agree with what you mentioned above and I was paranoid of that scenario too, hence the disabling of the code.

Purely going off from the docs, I don't think there's anywhere where Python provides an explicit expectation of what the behavior is of memory that survives a call to Py_Finalize. Furthermore, in the C-API it is specified that Py_Finalize will: "Undo all initializations made by Py_Initialize() and subsequent use of Python/C API functions". This gives an an implicit assumption that holding onto these interned strings after Py_Finalize is an undefined behavior.

Perhaps we should be more explicit about this in the docs (maybe in the "Bugs and Caveats" section of Py_Finalize)? i.e python can't guarantee correctness for any memory allocated during a python initialization and used in any subsequent initializations. Thoughts?

Regardless, I completely agree that we should still be careful about putting this out there. Stating with alphas sounds like a good idea to get some early signal. Let me know what's the best way to only enable this only for alphas.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eduardo-elizondo

eduardo-elizondo commented Jan 5, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Maybe we need to wait until we get python -X showrefcount showing zero for all or nearly all built-in and well known extensions?

I think we are already there? Here's a quick test program that I ran:

./python -X showrefcount -c "
import sys
import importlib
for mod in sys.modules.keys():
  importlib.import_module(mod)
"
[0 refs, 0 blocks]
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Jan 8, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Maybe we need to wait until we get python -X showrefcount showing zero for all or nearly all built-in and well known extensions?

It's mostly done for one year: https://mail.python.org/archives/list/[email protected]/thread/E4C6TDNVDPDNNP73HTGHN5W42LGAE22F/ "Mostly" means: some remaining stdlib C extensions still implement their own static types which are not cleared by _PyTypes_FiniTypes(), and/or don't use the multi-phase initialization API yet.

test_embed checks that python -c pass does not leak memory at Python exit: see MiscTests.test_no_memleak().

Purely going off from the docs, I don't think there's anywhere where Python provides an explicit expectation of what the behavior is of memory that survives a call to Py_Finalize.

This change is a backward incompatible. I suggest to just document well the change in What's New in Python 3.13:

  • Explain how to qualify if a crash is related to this issue,
  • Document how to update affected code.

In short, a program must not keep references to any Python object between Py_Finalize() and Py_Initialize(). IMO the general rule is calling Py_Finalize() converts all Python object pointers to dangling pointers. There are some very specific exceptions which should be listed with conditions, such as "only on CPython and it's an implementation detail which can change between two Python versions".

In general, I suggest to reset all pointers to Python objects at each Py_Initialize() call. Or said differently: don't store any pointer to Python objects after Py_Finalize() :-)

Examples of exceptions:

  • Immortal objects
  • Static types (built-in immortal objects are marked as immortal)
  • Singletons (built-in singleton objects are marked as immortal) such as: empty string, empty tuple, small integers (-5..256).
eduardo-elizondo and erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eduardo-elizondo

eduardo-elizondo commented Jan 8, 2024 •
edited by vstinner
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

This change is a backward incompatible. I suggest to just document well the change in What's New in Python 3.13

For sure, I can update the PR with the details with what you mentioned here!

It's mostly done for one year

Given this guarantee, I think it's safe to assume that if we have any Python object leak it's a user induced leak, right? i.e. the runtime itself will not cause incorrect behavior. I will include some wording around this so that users can isolate the surface are when looking for issues (i.e look at the third-party extensions not at the runtime).

In short, a program must not keep references to any Python object between Py_Finalize() and Py_Initialize()

That's my take too - though it's not specified in the docs! Any thoughts of also updating the Py_Finalize/Py_Initialize documentation as part of this PR to include stricter language like this?

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Jan 8, 2024

Copy link
Copy Markdown
Member

This change is a backward incompatible. I suggest to just document well the change in What's New in Python 3.13

I looked again at the code. It has a complicated history:

  • In Python 3.9 and older, interned strings were never deleted. Only special build for Valgrind and Purity cleared them at exit.
  • In Python 3.10 and 3.11, interned strings are always deleted at exit.
  • In Python 3.12, interned strings are deleted only if Python is built in debug mode: they are not deleted in release mode.

If there are applications relying on interned strings to survive between multiple Py_Initialize()/Py_Finalize() cycles, they should already be affected by Python 3.10 and 3.11.

By the way, Python 3.11 added _PyTypes_FiniTypes() to "clear" static types in Py_Finalize().

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

eduardo-elizondo added 2 commits January 15, 2024 17:37
@eduardo-elizondo
Merge remote-tracking branch 'upstream/main' into reenable_unicode_cl…
fd9c7ff
…ear_interned
@eduardo-elizondo
Add documentation
ed09466
@erlend-aasland erlend-aasland mentioned this pull request Jan 15, 2024
Interned strings are immortal, despite what the documentation says #113993
Closed
eduardo-elizondo added 5 commits January 15, 2024 18:35
@eduardo-elizondo
Lint docs
2608119
@eduardo-elizondo
Lint docs v2
17e8817
@eduardo-elizondo
Lint docs v3
dd1e8b4
@eduardo-elizondo
Lint docs v4
ce5536b
@eduardo-elizondo
Lint docs v5
071438f
@bedevere-app bedevere-app Bot added the awaiting merge label Aug 12, 2024
@encukou encukou added the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Aug 12, 2024
@bedevere-bot

bedevere-bot commented Aug 12, 2024

Copy link
Copy Markdown

🤖 New build scheduled with the buildbot fleet by @encukou for commit 6aee7f5 🤖

If you want to schedule another build, you need to add the 🔨 test-with-refleak-buildbots label again.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-bot bedevere-bot removed the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label Aug 12, 2024
@encukou
Update whatsnew
dc3b54f
@encukou
encukou enabled auto-merge (squash) August 15, 2024 11:28
@encukou
encukou merged commit 3203a74 into python:main Aug 15, 2024
@miss-islington-app

miss-islington-app Bot commented Aug 15, 2024

Copy link
Copy Markdown

Thanks @eduardo-elizondo for the PR, and @encukou for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12, 3.13.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Aug 15, 2024
@miss-islington-app

miss-islington-app Bot commented Aug 15, 2024

Copy link
Copy Markdown

Sorry, @eduardo-elizondo and @encukou, I could not cleanly backport this to 3.13 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 3203a7412977b8da3aba2770308136a37f48c927 3.13
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app miss-islington-app Bot assigned encukou Aug 15, 2024
@miss-islington-app

miss-islington-app Bot commented Aug 15, 2024

Copy link
Copy Markdown

Sorry, @eduardo-elizondo and @encukou, I could not cleanly backport this to 3.12 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 3203a7412977b8da3aba2770308136a37f48c927 3.12
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@eduardo-elizondo

eduardo-elizondo commented Aug 16, 2024

Copy link
Copy Markdown
Contributor Author

Thanks @encukou !!

ericsnowcurrently reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

blhsing pushed a commit to blhsing/cpython that referenced this pull request Aug 22, 2024
@eduardo-elizondo @blhsing
pythongh-113190: Reenable non-debug interned string cleanup (pythonGH…
b32350a
…-113601)
@sobolevn sobolevn mentioned this pull request Sep 9, 2024
gh-108303: Remove the non-test Lib/test/reperf.py #114356
Merged
@neonene

neonene commented Oct 14, 2024

Copy link
Copy Markdown
Contributor

Is there any chance this will be backported to 3.13.1?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

hugovk pushed a commit to hugovk/cpython that referenced this pull request Feb 26, 2025
@eduardo-elizondo @hugovk
[3.13] pythongh-113190: Reenable non-debug interned string cleanup (p…
0355566
…ythonGH-113601)

(cherry picked from commit 3203a74)

Co-authored-by: Eddie Elizondo <[email protected]>
@hugovk hugovk mentioned this pull request Feb 26, 2025
[3.13] gh-113190: Reenable non-debug interned string cleanup (GH-113601) #130581
Closed
@bedevere-app

bedevere-app Bot commented Feb 26, 2025

Copy link
Copy Markdown

GH-130581 is a backport of this pull request to the 3.13 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 only security fixes label Feb 26, 2025
hugovk pushed a commit to hugovk/cpython that referenced this pull request Feb 26, 2025
@eduardo-elizondo @hugovk
[3.12] pythongh-113190: Reenable non-debug interned string cleanup (p…
dccc2ed
…ythonGH-113601)

(cherry picked from commit 3203a74)

Co-authored-by: Eddie Elizondo <[email protected]>
@hugovk hugovk mentioned this pull request Feb 26, 2025
[3.12] gh-113190: Reenable non-debug interned string cleanup (GH-113601) #130582
Closed
@bedevere-app

bedevere-app Bot commented Feb 26, 2025

Copy link
Copy Markdown

GH-130582 is a backport of this pull request to the 3.12 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.12 only security fixes label Feb 26, 2025
@hugovk

hugovk commented Feb 26, 2025

Copy link
Copy Markdown
Member

The conflict preventing Miss Islington from backporting #113601 was the addition to Doc/whatsnew/3.14.rst.

I've made the backport PRs. Do we need any other docs in them?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@encukou

encukou commented Feb 26, 2025

Copy link
Copy Markdown
Member

Is there any chance this will be backported to 3.13.1?

Sorry, I missed the notification!

See this paragraph in the added docs:

Note that Python will do a best effort at freeing all memory allocated by the Python
interpreter. Therefore, any C-Extension should make sure to correctly clean up all
of the preveiously allocated PyObjects before using them in subsequent calls to
:c:func:Py_Initialize. Otherwise it could introduce vulnerabilities and incorrect
behavior.

In other words, it's possible that some extensions will start crashing after Py_Finalize & Py_Initialize.
It would only be extensions that used the API incorreclty, but, that's little consolation for affected users.

I don't think we should backport to bugfix branches, unfortunately.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

hugovk commented Feb 26, 2025

Copy link
Copy Markdown
Member

I don't think we should backport to bugfix branches, unfortunately.

Okay, I'll close the backports.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@heitbaum heitbaum mentioned this pull request Mar 7, 2025
Python: update to 3.13.5 LibreELEC/LibreELEC.tv#9374
Merged
jcfr added a commit to jcfr/MeVisLab-pythonqt that referenced this pull request Sep 4, 2025
@jcfr
ci(tests): suppress CPython 3.12 interned-unicode leak (PyUnicode_New…
8871ee9
…) in sanitizer runs

Under ASan/LSan with Python 3.12 on Ubuntu 22.04/24.04, the cleanup tests
report direct leaks rooted in CPython’s unicode interning path (frames via
PyUnicode_New) during module import in our embedded init.

This is a known CPython issue (python/cpython#113190). Interned-unicode
cleanup was re-enabled in 3.13 (python/cpython#113601) but not backported
to 3.12. To keep CI signal meaningful while we still test against 3.12,
enable a narrow LSan suppression for PyUnicode_New only, and only on 3.12.

Notes:
- detect_leaks=1 remains enabled; the suppression is limited to PyUnicode_New
  and won’t mask leaks in PythonQt.
- Remove once CI moves off Python 3.12.

Refs: python/cpython#113190, python/cpython#113601
mrbean-bremen pushed a commit to MeVisLab/pythonqt that referenced this pull request Sep 4, 2025
@jcfr @mrbean-bremen
ci(tests): suppress CPython 3.12 interned-unicode leak (PyUnicode_New…
b4fc6ee
…) in sanitizer runs

Under ASan/LSan with Python 3.12 on Ubuntu 22.04/24.04, the cleanup tests
report direct leaks rooted in CPython’s unicode interning path (frames via
PyUnicode_New) during module import in our embedded init.

This is a known CPython issue (python/cpython#113190). Interned-unicode
cleanup was re-enabled in 3.13 (python/cpython#113601) but not backported
to 3.12. To keep CI signal meaningful while we still test against 3.12,
enable a narrow LSan suppression for PyUnicode_New only, and only on 3.12.

Notes:
- detect_leaks=1 remains enabled; the suppression is limited to PyUnicode_New
  and won’t mask leaks in PythonQt.
- Remove once CI moves off Python 3.12.

Refs: python/cpython#113190, python/cpython#113601
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@nascheme nascheme nascheme left review comments
@encukou encukou encukou approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@encukou encukou

Labels

interpreter-core (Objects, Python, Grammar, and Parser dirs) skip news

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

10 participants

@eduardo-elizondo @Eclips4 @nascheme @vstinner @neonene @ericsnowcurrently @encukou @bedevere-bot @hugovk @serhiy-storchaka
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.