[v2,1/3,gdb/python] Factor out and refactor py_initialize

Message ID 20241128125739.1758-2-tdevries@suse.de
State Committed
Headers
Series Python initialization-related fixes |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Tom de Vries Nov. 28, 2024, 12:57 p.m. UTC
  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.
---
 gdb/python/python.c | 79 ++++++++++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 30 deletions(-)
  

Patch

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