https://github.com/python/cpython/commit/35a000974a97248ffe4137ac01373f391cfc3728
commit: 35a000974a97248ffe4137ac01373f391cfc3728
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-16T10:49:53Z
summary:

Revert "gh-158445: Allocate memory in the heap in Py_GetVersion() (#158608)" 
(#159519)

This reverts commit f5e913c7f710794421e48437f45a65f190830cbf.

Truncating the static buffer to 20 bytes caused a regression in debuggers
and crash reporters checking `version` static buffer, see:
https://github.com/python/cpython/pull/158608#issuecomment-6027641907

files:
M Doc/c-api/interp-lifecycle.rst
M Include/internal/pycore_pylifecycle.h
M Lib/test/test_capi/test_build.py
M Modules/main.c
M Python/getcompiler.c
M Python/getversion.c
M Python/pylifecycle.c
M Tools/c-analyzer/cpython/ignored.tsv

diff --git a/Doc/c-api/interp-lifecycle.rst b/Doc/c-api/interp-lifecycle.rst
index a43298d44bdc1cf..7cfde5cdae6c566 100644
--- a/Doc/c-api/interp-lifecycle.rst
+++ b/Doc/c-api/interp-lifecycle.rst
@@ -514,7 +514,7 @@ Process-wide parameters
    Return the version of this Python interpreter.  This is a string that looks
    something like ::
 
-      "3.15.0rc2 (3.15.0~rc2-1.fc44.x86_64, Sep  3 2026, 00:00:00) [GCC 16.2.1 
20260819 (Red Hat 16.2.1-2)]"
+      "3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
 
    .. index:: single: version (in module sys)
 
diff --git a/Include/internal/pycore_pylifecycle.h 
b/Include/internal/pycore_pylifecycle.h
index 99d09c5e0d4e113..bfc94e3e8529b75 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -23,7 +23,7 @@ extern int _Py_IsLocaleCoercionTarget(const char *ctype_loc);
 
 /* Various one-time initializers */
 
-extern PyStatus _Py_GetVersion_Init(void);
+extern void _Py_InitVersion(void);
 extern PyStatus _PyFaulthandler_Init(int enable);
 extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp);
 extern int _PyBuiltin_InitPythonFunctions(PyObject *dict);
@@ -43,7 +43,6 @@ extern PyStatus _PyDateTime_InitTypes(PyInterpreterState 
*interp);
 
 /* Various internal finalizers */
 
-extern void _Py_GetVersion_Fini(void);
 extern int _PySignal_Init(int install_signal_handlers);
 extern void _PySignal_Fini(void);
 
diff --git a/Lib/test/test_capi/test_build.py b/Lib/test/test_capi/test_build.py
index d45c9dbc1c58825..8319ad1ec77da81 100644
--- a/Lib/test/test_capi/test_build.py
+++ b/Lib/test/test_capi/test_build.py
@@ -20,11 +20,15 @@ def test_getcopyright(self):
 
     # Test Py_GetCompiler()
     def test_getcompiler(self):
-        self.assertIn(_testlimitedcapi.py_getcompiler(), sys.version)
+        compiler = _testlimitedcapi.py_getcompiler()
+        self.assertIsInstance(compiler, str)
+        self.assertNotEqual(compiler, '')
 
     # Test Py_GetBuildInfo()
     def test_getbuildinfo(self):
-        self.assertIn(_testlimitedcapi.py_getbuildinfo(), sys.version)
+        buildinfo = _testlimitedcapi.py_getbuildinfo()
+        self.assertIsInstance(buildinfo, str)
+        self.assertNotEqual(buildinfo, '')
 
     # Test internal _Py_GetBuiltWithAssert()
     def test__getbuiltwithassert(self):
diff --git a/Modules/main.c b/Modules/main.c
index 097c10504d69a36..44a025d500e35e2 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -847,7 +847,6 @@ pymain_free(void)
     _PyPathConfig_ClearGlobal();
     _Py_ClearArgcArgv();
     _PyRuntime_Finalize();
-    _Py_GetVersion_Fini();
 }
 
 
diff --git a/Python/getcompiler.c b/Python/getcompiler.c
index baa03679d79fb84..cc56ad8c8955513 100644
--- a/Python/getcompiler.c
+++ b/Python/getcompiler.c
@@ -3,7 +3,6 @@
 
 #include "Python.h"
 
-// PC/pyconfig.h defines _Py_COMPILER
 #ifdef _Py_COMPILER
 #  define COMPILER _Py_COMPILER
 #endif
@@ -13,14 +12,14 @@
 // Note the __clang__ conditional has to come before the __GNUC__ one because
 // clang pretends to be GCC.
 #if defined(__clang__)
-#  define COMPILER "[Clang " __clang_version__ "]"
+#define COMPILER "[Clang " __clang_version__ "]"
 #elif defined(__GNUC__)
-#  define COMPILER "[GCC " __VERSION__ "]"
+#define COMPILER "[GCC " __VERSION__ "]"
 // Generic fallbacks.
 #elif defined(__cplusplus)
-#  define COMPILER "[C++]"
+#define COMPILER "[C++]"
 #else
-#  define COMPILER "[C]"
+#define COMPILER "[C]"
 #endif
 
 #endif /* !COMPILER */
diff --git a/Python/getversion.c b/Python/getversion.c
index 5c05b841de6fc84..8d8bc6ea70048c9 100644
--- a/Python/getversion.c
+++ b/Python/getversion.c
@@ -2,77 +2,32 @@
 /* Return the full version string. */
 
 #include "Python.h"
-#include "pycore_initconfig.h"    // _PyStatus_NO_MEMORY()
 
+#include "patchlevel.h"
 
 static int initialized = 0;
-// Use the smallest possible buffer: it's only needed if malloc() fails *and*
-// Py_GetVersion() is called before Py_Initialize(). The buffer should be big
-// enough to store "3.16.0a0 " string.
-static char static_version[20];
-static char *heap_version = NULL;
+static char version[300];
 
-
-PyStatus
-_Py_GetVersion_Init(void)
+void _Py_InitVersion(void)
 {
     if (initialized) {
-        return _PyStatus_OK();
+        return;
     }
-
+    initialized = 1;
 #ifdef Py_GIL_DISABLED
-    const char *format = "%s free-threading build (%s) %s";
-    size_t format_len = strlen(" free-threading build () ");
+    const char *buildinfo_format = "%.80s free-threading build (%.80s) %.80s";
 #else
-    const char *format = "%s (%s) %s";
-    size_t format_len = strlen(" () ");
+    const char *buildinfo_format = "%.80s (%.80s) %.80s";
 #endif
-    const char *version_str = PY_VERSION;
-    const char *buildinfo = Py_GetBuildInfo();
-    const char *compiler = Py_GetCompiler();
-    // +1 for the trailing NUL byte
-    size_t len = (format_len + strlen(version_str) + strlen(buildinfo)
-                  + strlen(compiler) + 1);
-
-    // Always format the static version
-    PyOS_snprintf(static_version, sizeof(static_version), format,
-                  version_str, buildinfo, compiler);
-
-    heap_version = malloc(len);
-    if (heap_version == NULL) {
-        // If malloc() failed, don't set initialized to 1, so next
-        // Py_GetVersion() will try again to allocate memory.
-        return _PyStatus_NO_MEMORY();
-    }
-
-    PyOS_snprintf(heap_version, len, format,
-                  version_str, buildinfo, compiler);
-    initialized = 1;
-    return _PyStatus_OK();
-}
-
-void
-_Py_GetVersion_Fini(void)
-{
-    if (heap_version) {
-        free(heap_version);
-        heap_version = NULL;
-    }
+    PyOS_snprintf(version, sizeof(version), buildinfo_format,
+                  PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler());
 }
 
 const char *
 Py_GetVersion(void)
 {
-    PyStatus status = _Py_GetVersion_Init();
-    // Ignore error: Py_GetVersion() API cannot report error
-    (void)status;
-
-    if (heap_version) {
-        return heap_version;
-    }
-    else {
-        return static_version;
-    }
+    _Py_InitVersion();
+    return version;
 }
 
 // Export the Python hex version as a constant.
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index ba1b94c47984ab6..8888f523559123a 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -559,11 +559,7 @@ pycore_init_runtime(_PyRuntimeState *runtime,
      */
     _PyRuntimeState_SetFinalizing(runtime, NULL);
 
-    status = _Py_GetVersion_Init();
-    if (_PyStatus_EXCEPTION(status)) {
-        return status;
-    }
-
+    _Py_InitVersion();
     _Py_DumpTraceback_Init();
 
     status = _Py_HashRandomization_Init(config);
diff --git a/Tools/c-analyzer/cpython/ignored.tsv 
b/Tools/c-analyzer/cpython/ignored.tsv
index 5529a52b0c45c26..db9f74fdbc591f0 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -48,8 +48,7 @@ Objects/unicodeobject.c       _init_global_state      
initialized     -
 Modules/getbuildinfo.c -       buildinfo       -
 Modules/getbuildinfo.c -       initialized     -
 Python/getversion.c    -       initialized     -
-Python/getversion.c    -       static_version  -
-Python/getversion.c    -       heap_version    -
+Python/getversion.c    -       version -
 
 ## public C-API - set during first init
 Python/bootstrap_hash.c        -       _Py_HashSecret_Initialized      -

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to