[binutils-gdb] [gdb/python] Factor out and refactor py_initialize

Tom de Vries vries@sourceware.org
Tue Dec 3 21:48:27 GMT 2024


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=125f702105d1ee1fd111d370c6f99fbe96f63899

commit 125f702105d1ee1fd111d370c6f99fbe96f63899
Author: Tom de Vries <tdevries@suse.de>
Date:   Tue Dec 3 22:49:40 2024 +0100

    [gdb/python] Factor out and refactor py_initialize
    
    Function do_start_initialization has a large part dedicated to initializing
    the python interpreter, as opposed to the rest of the function where
    gdb-specific python support is initialized.
    
    Factor out this part, as new function py_initialize, and rename the existing
    py_initialize to py_initialize_catch_abort.
    
    Refactor the new function py_initialize by getting rid of the nested:
    ...
     #ifdef WITH_PYTHON_PATH
     #if PY_VERSION_HEX < 0x030a0000
     #else
     #endif
     #else
     #endif
    ...
    
    In particular, this changes behaviour for the "!defined (WITH_PYTHON_PATH)"
    case.
    
    For the "defined (WITH_PYTHON_PATH)" case, we've started using
    Py_InitializeFromConfig () for PY_VERSION_HEX >= 0x030a0000 to deal with the
    deprecation of Py_SetProgramName in 3.11.
    
    For the "!defined (WITH_PYTHON_PATH)" case, we don't use Py_SetProgramName so
    we stuck with Py_Initialize ().
    
    However, in 3.12 Py_DontWriteBytecodeFlag and Py_IgnoreEnvironmentFlag got
    deprecated and also here we need Py_InitializeFromConfig () to deal with this,
    but the "!defined (WITH_PYTHON_PATH)" case didn't get updated.
    
    This should be taken care of, now that we have this behavior:
    - for PY_VERSION_HEX < 0x030a0000 we use Py_Initialize
    - for PY_VERSION_HEX >= 0x030a0000 we use Py_InitializeFromConfig
    
    I'm not sure how to test the "!defined (WITH_PYTHON_PATH)" though.
    
    Tested on aarch64-linux.
    
    Approved-By: Tom Tromey <tom@tromey.com>

Diff:
---
 gdb/python/python.c | 79 +++++++++++++++++++++++++++++++++--------------------
 1 file changed, 49 insertions(+), 30 deletions(-)

diff --git a/gdb/python/python.c b/gdb/python/python.c
index 3dc56d5695d..eb8d35ff04e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -2318,7 +2318,7 @@ static bool py_isinitialized = false;
 /* Call Py_Initialize (), and return true if successful.   */
 
 static bool ATTRIBUTE_UNUSED
-py_initialize ()
+py_initialize_catch_abort ()
 {
   auto prev_handler = signal (SIGABRT, catch_python_fatal);
   SCOPE_EXIT { signal (SIGABRT, prev_handler); };
@@ -2336,20 +2336,25 @@ py_initialize ()
   return py_isinitialized;
 }
 
+/* Initialize python, either by calling Py_Initialize or
+   Py_InitializeFromConfig, and return true if successful.  */
+
 static bool
-do_start_initialization ()
+py_initialize ()
 {
-  /* Define all internal modules.  These are all imported (and thus
-     created) during initialization.  */
-  struct _inittab mods[] =
-  {
-    { "_gdb", init__gdb_module },
-    { "_gdbevents", gdbpy_events_mod_func },
-    { nullptr, nullptr }
-  };
-
-  if (PyImport_ExtendInittab (mods) < 0)
-    return false;
+#if PY_VERSION_HEX < 0x030a0000
+  /* Python documentation indicates that the memory given
+     to Py_SetProgramName cannot be freed.  However, it seems that
+     at least Python 3.7.4 Py_SetProgramName takes a copy of the
+     given program_name.  Making progname_copy static and not release
+     the memory avoids a leak report for Python versions that duplicate
+     program_name, and respect the requirement of Py_SetProgramName
+     for Python versions that do not duplicate program_name.  */
+  static wchar_t *progname_copy = nullptr;
+#else
+  wchar_t *progname_copy = nullptr;
+  SCOPE_EXIT { XDELETEVEC (progname_copy); };
+#endif
 
 #ifdef WITH_PYTHON_PATH
   /* Work around problem where python gets confused about where it is,
@@ -2361,14 +2366,6 @@ do_start_initialization ()
   gdb::unique_xmalloc_ptr<char> progname
     (concat (ldirname (python_libdir.c_str ()).c_str (), SLASH_STRING, "bin",
 	      SLASH_STRING, "python", (char *) NULL));
-  /* Python documentation indicates that the memory given
-     to Py_SetProgramName cannot be freed.  However, it seems that
-     at least Python 3.7.4 Py_SetProgramName takes a copy of the
-     given program_name.  Making progname_copy static and not release
-     the memory avoids a leak report for Python versions that duplicate
-     program_name, and respect the requirement of Py_SetProgramName
-     for Python versions that do not duplicate program_name.  */
-  static wchar_t *progname_copy;
 
   {
     std::string oldloc = setlocale (LC_ALL, NULL);
@@ -2384,6 +2381,7 @@ do_start_initialization ()
 	return false;
       }
   }
+#endif
 
   /* Py_SetProgramName was deprecated in Python 3.11.  Use PyConfig
      mechanisms for Python 3.10 and newer.  */
@@ -2391,17 +2389,21 @@ do_start_initialization ()
   /* Note that Py_SetProgramName expects the string it is passed to
      remain alive for the duration of the program's execution, so
      it is not freed after this call.  */
-  Py_SetProgramName (progname_copy);
-  if (!py_initialize ())
-    return false;
+  if (progname_copy != nullptr)
+    Py_SetProgramName (progname_copy);
+  return py_initialize_catch_abort ();
 #else
   PyConfig config;
 
   PyConfig_InitPythonConfig (&config);
-  PyStatus status = PyConfig_SetString (&config, &config.program_name,
-					progname_copy);
-  if (PyStatus_Exception (status))
-    goto init_done;
+  PyStatus status;
+  if (progname_copy != nullptr)
+    {
+      status = PyConfig_SetString (&config, &config.program_name,
+				   progname_copy);
+      if (PyStatus_Exception (status))
+	goto init_done;
+    }
 
   config.write_bytecode = python_write_bytecode ();
   config.use_environment = !python_ignore_environment;
@@ -2423,12 +2425,29 @@ do_start_initialization ()
 		    status.exitcode);
       return false;
     }
+
   py_isinitialized = true;
+  return true;
 #endif
-#else
+}
+
+static bool
+do_start_initialization ()
+{
+  /* Define all internal modules.  These are all imported (and thus
+     created) during initialization.  */
+  struct _inittab mods[] =
+  {
+    { "_gdb", init__gdb_module },
+    { "_gdbevents", gdbpy_events_mod_func },
+    { nullptr, nullptr }
+  };
+
+  if (PyImport_ExtendInittab (mods) < 0)
+    return false;
+
   if (!py_initialize ())
     return false;
-#endif
 
 #if PY_VERSION_HEX < 0x03090000
   /* PyEval_InitThreads became deprecated in Python 3.9 and will


More information about the Gdb-cvs mailing list