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-158445: Allocate memory in the heap in Py_GetVersion() by vstinner · Pull Request #158608 · python/cpython

Conversation

@vstinner

@vstinner vstinner commented Oct 2, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

Py_GetVersion() now allocates memory on the heap, instead of using a static buffer, to no longer truncate the version if it's longer than 299 bytes.

Update Py_GetCompiler() and Py_GetBuildInfo() tests: they are now always a part of sys.version.

  • Issue: C API: Detect invalid UCS4 characters in debug mode #158445

Sorry, something went wrong.

Uh oh!

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

chris-eibl reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@vstinner
pythongh-158445: Allocate memory in the heap in Py_GetVersion()
c937f76
Py_GetVersion() now allocates memory on the heap, instead of using a
static buffer, to no longer truncate the version if it's longer than
299 bytes.

Update Py_GetCompiler() and Py_GetBuildInfo() tests: they are now
always a part of sys.version.
@vstinner
vstinner requested review from FFY00, ZeroIntensity and ericsnowcurrently as code owners October 2, 2026 16:39
@vstinner vstinner added the skip news label Oct 2, 2026
@bedevere-app bedevere-app Bot mentioned this pull request Oct 2, 2026
C API: Detect invalid UCS4 characters in debug mode #158445
Closed
@bedevere-app bedevere-app Bot added the awaiting core review label Oct 2, 2026
@vstinner vstinner mentioned this pull request Oct 2, 2026
Fix clang-cl version in sys.version on Windows #157368
Closed
@read-the-docs-community

read-the-docs-community Bot commented Oct 2, 2026 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #34907310 | 📁 Comparing ef0a101 against main (be87a85)

  🔍 Preview build  

2 files changed
± c-api/interp-lifecycle.html
± whatsnew/changelog.html
All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner
Fix make check-c-globals
ef0a101
@vstinner

vstinner commented Oct 3, 2026

Copy link
Copy Markdown
Member Author

On my Fedora 44, __clang_version__ is short: 22.1.8 (Fedora 22.1.8-4.fc44). But in issue gh-157368, way longer version has been seen: 22.1.3 (https://github.com/llvm/llvm-project e9846648fd6183ee6d8cbdb4502213fcf902a211). On Windows, PC/pyconfig.h no longer uses __clang_version__. But we may such long clang version on other platforms.

All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner
vstinner merged commit f5e913c into python:main Oct 3, 2026
54 checks passed

Uh oh!

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

@vstinner
vstinner deleted the getversion branch October 3, 2026 13:15
@bedevere-app bedevere-app Bot removed the awaiting core review label Oct 3, 2026
@vstinner vstinner mentioned this pull request Oct 3, 2026
gh-158445: Add C API tests on build information functions #158603
Merged
@itamaro

itamaro commented Oct 6, 2026 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor

hey @vstinner, we ran into a side effect of moving the buffer to the heap - some debuggers and core-dump tools find the interpreter version by reading the Py_GetVersion() buffer out of process memory (py-spy for example). With only the 20-byte static_version left, they lose the tag and the "free-threading build" marker. Getting those back means following heap_version into the heap, which is fragile and not always possible.

can we make the static buffer bigger, at least enough to hold the version, tag, and free-threading marker (~64 bytes)? let me know if I should file a separate issue

All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner

vstinner commented Oct 7, 2026

Copy link
Copy Markdown
Member Author

py-spy:

    if let Some(&addr) = python_info.get_symbol("Py_GetVersion.version") {
        info!("Getting version from symbol address");
        if let Ok(bytes) = process.copy(addr as usize, 128) {
            if let Ok(version) = Version::scan_bytes(&bytes) {
                return Ok(version);
            }
        }
    }

I understand that in Python 3.15, py-spy copies 128 bytes from the static char version[300]; variable.

Would it be possible for py-spy to (1) call Py_GetVersion() function and (2) copy the return string? I suppose that it's better to not call functions in a debugger to leave the process state unchanged.

some debuggers and core-dump tools find the interpreter version by reading the Py_GetVersion() buffer out of process memory (py-spy for example)

I didn't think about these use cases. That's not how I expected the Python C API to be used. Well, they just inspect memory, they don't even call functions, if I understand correctly.

@itamaro:

can we make the static buffer bigger, at least enough to hold the version, tag, and free-threading marker (~64 bytes)? let me know if I should file a separate issue

Would you recommend to revert my change and add a comment explaining the debugger/crash reporter use cases?

Or just restore the static buffer to its Python 3.15 size (300 bytes)? I suppose that the static buffer name should be restored to version, so debuggers/crash reporters don't have to update their code.

Thanks for rising the issue!

All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner vstinner mentioned this pull request Oct 7, 2026
Rework Modules/getbuildinfo.c to build strings at build time, instead of runtime #158948
Open
@vstinner

vstinner commented Oct 7, 2026

Copy link
Copy Markdown
Member Author

Or there is another approach, build strings at build time, to avoid the complex code building strings at runtime: #158951.

All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner vstinner mentioned this pull request Oct 7, 2026
gh-158948: Generate Modules/getbuildinfo.h #158951
Open
@itamaro

itamaro commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

I understand that in Python 3.15, py-spy copies 128 bytes from the static char version[300]; variable.

Would it be possible for py-spy to (1) call Py_GetVersion() function and (2) copy the return string? I suppose that it's better to not call functions in a debugger to leave the process state unchanged.

yeah, I think not calling function in the debugged process is the point. for core-dump tools, there isn't even a process around.

I didn't think about these use cases. That's not how I expected the Python C API to be used. Well, they just inspect memory, they don't even call functions, if I understand correctly.

sounds right. like you say, they're inspecting memories, not "using" the C API per se.

Would you recommend to revert my change and add a comment explaining the debugger/crash reporter use cases?

Or just restore the static buffer to its Python 3.15 size (300 bytes)? I suppose that the static buffer name should be restored to version, so debuggers/crash reporters don't have to update their code.

I don't think we need to revert, just restoring the version static buffer should be sufficient!

thanks for looking into this! I didn't look closely at your gh-158951, it looks like a bigger change than just restoring the static buffer, so if you think that's the better way to go, I may be able to test it in the next few days, or maybe next week.

vstinner 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 Oct 8, 2026

Copy link
Copy Markdown
Member Author

thanks for looking into this! I didn't look closely at your #158951, it looks like a bigger change than just restoring the static buffer, so if you think that's the better way to go, I may be able to test it in the next few days, or maybe next week.

I created https://discuss.python.org/t/generate-modules-getbuildinfo-h-when-building-python-to-get-build-information-statically/109401 to discuss my change. The backup plan is to revert my change and just make the static version buffer larger (350 bytes?) to support very long Clang version strings.

All reactions

Sorry, something went wrong.

Uh oh!

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

@itamaro

itamaro commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

thanks for making gh-158951 @vstinner ! I looked at it and did some testing, and here are my thoughts:

  1. I don't have a strong opinion about generating the strings at build time, so I'll leave that to the issue/PR where there's already ongoing discussion.
  2. if possible, I’d like to decouple fixing the regression from the rework. reinstating the version static buffer should be a quick, safe PR that doesn't need to wait on the bigger design discussion. happy to put a PR if it helps.
  3. as implemented in gh-158948: Generate Modules/getbuildinfo.h #158951, the issue I raised isn't fixed. version is now a pointer rather than a buffer, and with gcc and clang at -O2 the variable is optimized out entirely, leaving only an unnamed string in .rodata.

to be more concrete about the use case: what broke for us is an lldb-based Python debugging extension that we use on live processes and on core dumps. on a core you can't call Py_GetVersion(), so it reads the string from memory. it can't rely on the symbol name either (with LTO the static becomes version.llvm.<hash>), so it scans .bss for the version pattern. a string in .rodata doesn't work for that, since it isn't in .bss, and default Linux core dumps don't include unmodified file-backed mappings like .rodata.

I tested this against our debugger test suite. with gh-158951 applied, it fails to detect the Python runtime. a named static const char version[] = VERSION; doesn't help either, since it's still in .rodata. a static char version[300] in .bss, filled at startup, passes everything.

what we actually use is the start of the string: version, local version suffix (3.16.0a0+meta), and the free-threading marker. a 20-byte fallback would cut off before the free-threading marker.

_Py_DebugOffsets covers most of this. I checked that _PyRuntime is in default core dumps with the cookie, version and free_threaded readable, and we already take free_threaded from there. what's missing is the suffix, which we use to pick build-specific struct offsets when debug info isn't available. if _Py_DebugOffsets exposed the PY_VERSION string, tools could move off the buffer for 3.16+, but that's a separate, bigger change, and older versions would still need the buffer.

so my concrete proposal is to keep static char version[~300] in .bss, filled at startup with the full/truncated string, as in 3.15. we only need roughly the first 64 bytes, but 300 matches what existing tools have always seen.

All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner

vstinner commented Oct 16, 2026

Copy link
Copy Markdown
Member Author

I was busy fixing other issues in the meanwhile, I didn't find time to finish PR gh-158951.

Since you seem to be affected by a regression, I created PR #159519 to simply revert my change allocating memory on the heap.

itamaro and chris-eibl reacted with heart emoji
All reactions
  • ❤️ 2 reactions

Sorry, something went wrong.

Uh oh!

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

vstinner added a commit that referenced this pull request Oct 16, 2026
@vstinner
Revert "gh-158445: Allocate memory in the heap in Py_GetVersion() (#1…
35a0009
…58608)" (#159519)

This reverts commit f5e913c.

Truncating the static buffer to 20 bytes caused a regression in debuggers
and crash reporters checking `version` static buffer, see:
#158608 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@ericsnowcurrently ericsnowcurrently Awaiting requested review from ericsnowcurrently ericsnowcurrently is a code owner
@ZeroIntensity ZeroIntensity Awaiting requested review from ZeroIntensity ZeroIntensity is a code owner
@FFY00 FFY00 Awaiting requested review from FFY00 FFY00 is a code owner

Uh oh!

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

Assignees

No one assigned

Labels

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.

2 participants

@vstinner @itamaro
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.