[binutils-gdb] [gdb/python] Handle error in gdbpy_initialize_gdb_readline

Tom de Vries via Gdb-cvs <[email protected]>
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=25f1035f403c929a38d822f0525ec1bb180fffb5

commit 25f1035f403c929a38d822f0525ec1bb180fffb5
Author: Tom de Vries <[email protected]>
Date:   Wed Aug 12 23:11:46 2026 +0200

    [gdb/python] Handle error in gdbpy_initialize_gdb_readline
    
    On Fedora Rawhide aarch64-linux, with test-case gdb.python/py-failed-init.exp
    I ran into:
    ...
    builtin_spawn $build/gdb/gdb -nw -nx -q -iex set height 0 -iex set width 0 \
      -data-directory $build/gdb/data-directory -iex set interactive-mode on
    WARN: Could not find the standard library directory! The Python 'home' \
      directory was set to 'foo', is this correct?
    Error occurred computing Python error message.
    $build/gdb/gdb: warning:
    Could not load the Python gdb module from `$build/gdb/data-directory/python'.
    Limited Python support is available from the _gdb module.
    Suggest passing --data-directory=/path/to/gdb/data-directory.
    (gdb) set height 0
    (gdb) set width 0
    (gdb) dir
    Reinitialize source path to empty? (y or n) y
    Source directories searched: $cdir:$cwd
    (gdb) dir $src/gdb/testsuite/gdb.python
    Source directories searched: $src/gdb/testsuite/gdb.python:$cdir:$cwd
    (gdb) python print (1)
    1
    (gdb) FAIL: $exp: gdb-command<python print (1)>
    quit
    Exception ignored on threading shutdown:
    Traceback (most recent call last):
      File "<string>", line 2, in <module>
    ModuleNotFoundError: No module named 'importlib'
    PASS: $exp: quit
    ...
    
    The test-case tries to break python:
    ...
    save_vars { env(PYTHONHOME) } {
        setenv PYTHONHOME foo
        clean_restart
    }
    ...
    enough to get it to this point:
    ...
    gdb_test "python print (1)" \
        "Python not initialized"
    ...
    but apparently, that doesn't work anymore in this python version:
    ...
    $ python --version
    Python 3.15.0b4
    ...
    
    The test-case needs updating, and I've submitted a testsuite patch [1] for
    that.
    
    The next question is why we're seeing a ModuleNotFoundError on quit.
    
    I investigated this, and found that it originates from
    gdbpy_initialize_gdb_readline, where we do:
    ...
       if (eval_python_command (code, Py_file_input) == 0)
        PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
    ...
    but don't report and reset the python error state, so instead the error is
    reported by Py_Finalize.
    
    Fix this by:
    - making sure that the error is reported immediately, though in the form of a
      warning rather than an error, and
    - disabling the python-interactive command if gdbpy_initialize_gdb_readline
      fails, to avoid broken readline behavior in a python-interactive session.
    
    Also make the test-case a bit stricter by checking that there's no output when
    quitting.
    
    Tested on aarch64-linux.
    
    Approved-By: Tom Tromey <[email protected]>
    
    Changes in v2:
    - use gdbpy_print_stack instead of PyErr_Print/PyErr_Clear
    - Fix error/warning message by ensure that command name is double-quoted and
      displayed using command_style
    
    Versions:
    - v1 https://sourceware.org/pipermail/gdb-patches/2026-August/229261.html
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34485
    
    [1] https://sourceware.org/pipermail/gdb-patches/2026-August/229193.html

Diff:
---
 gdb/python/py-gdb-readline.c                | 17 +++++++++++++++++
 gdb/python/python-internal.h                |  5 +++++
 gdb/python/python.c                         |  4 ++++
 gdb/testsuite/gdb.python/py-failed-init.exp |  6 ++++++
 4 files changed, 32 insertions(+)

diff --git a/gdb/python/py-gdb-readline.c b/gdb/python/py-gdb-readline.c
index e8e2c23547c..1bb83adcc42 100644
--- a/gdb/python/py-gdb-readline.c
+++ b/gdb/python/py-gdb-readline.c
@@ -19,7 +19,9 @@
 
 #include "python-internal.h"
 #include "top.h"
+#include "ui-out.h"
 #include "cli/cli-utils.h"
+#include "cli/cli-style.h"
 
 /* Readline function suitable for PyOS_ReadlineFunctionPointer, which
    is used for Python's interactive parser and raw_input.  In both
@@ -116,8 +118,23 @@ sys.meta_path.insert(2, GdbRemoveReadlineFinder())\n\
 ";
   if (eval_python_command (code, Py_file_input) == 0)
     PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
+  else
+    {
+      gdbpy_print_stack ();
+
+      warning (_("Disabling import readline failed, \"%ps\" command disabled"),
+	       styled_string (command_style.style (), "python-interactive"));
+    }
 
   return 0;
 }
 
+/* See python-internal.h.  */
+
+bool
+gdbpy_import_readline_disabled ()
+{
+  return PyOS_ReadlineFunctionPointer == gdbpy_readline_wrapper;
+}
+
 GDBPY_INITIALIZE_FILE (gdbpy_initialize_gdb_readline);
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1165f165e29..3be1cc3ad55 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -1391,4 +1391,9 @@ py_notimplemented ()
 #include "py-wrappers.h"
 #include "py-safety.h"
 
+/* Return true if import readline was successfully disabled during
+   initialization.  */
+
+extern bool gdbpy_import_readline_disabled ();
+
 #endif /* GDB_PYTHON_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 7b5de98b903..0d6134ef060 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -383,6 +383,10 @@ eval_python_command (const char *command, int start_symbol,
 static void
 python_interactive_command (const char *arg, int from_tty)
 {
+  if (!gdbpy_import_readline_disabled ())
+    error (_("Disabling import readline failed, \"%ps\" command disabled"),
+	   styled_string (command_style.style (), "python-interactive"));
+
   struct ui *ui = current_ui;
   int err;
 
diff --git a/gdb/testsuite/gdb.python/py-failed-init.exp b/gdb/testsuite/gdb.python/py-failed-init.exp
index 622743d8d9b..c2b9c990e29 100644
--- a/gdb/testsuite/gdb.python/py-failed-init.exp
+++ b/gdb/testsuite/gdb.python/py-failed-init.exp
@@ -24,8 +24,14 @@ save_vars { env(PYTHONHOME) } {
 gdb_test "python print (1)" \
     "Python not initialized"
 
+set output_seen 0
 gdb_test_multiple "quit" "" {
+    -re ^quit\r\n {
+	exp_continue
+    }
     eof {
+	set output_seen [expr [string length $expect_out(buffer)] != 0]
 	pass $gdb_test_name
     }
 }
+gdb_assert {!$output_seen} "no output after quit"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.