[PING] Python: Fix Python error when "Quit"ting a paged info pretty-printers

Message ID 1458046365-21110-1-git-send-email-leonardo.boquillon@tallertechnologies.com
State New, archived
Headers

Commit Message

Leonardo Boquillon March 15, 2016, 12:52 p.m. UTC
  Right now the "Quit" command used in the output paging is handled as an exception.
If we issue a "Quit" while outputting the registered pretty-printers list, the
Python handling layer will catch it and think it's a Python error.

The fix is to check if the error coming from Python is a Quit signal. If it is,
do not handle it as an error and resume the execution normally.

Is this ok to commit? I have a company-wide copyright assignment and a coworker
of mine is a write-after-approval maintainer.

gdb/ChangeLog:
2016-03-08  Leonardo Boquillon  <leonardo.boquillon@tallertechnologies.com>

	* python/py-cmd.c (cmdpy_function): Handle the "Quit" exception.

---
 gdb/python/py-cmd.c | 85 +++++++++++++++++++++++++++++------------------------
 1 file changed, 47 insertions(+), 38 deletions(-)
  

Comments

Pedro Alves March 15, 2016, 3:45 p.m. UTC | #1
Hi Leonardo,

On 03/15/2016 12:52 PM, Leonardo Boquillon wrote:
> Right now the "Quit" command used in the output paging is handled as an exception.
> If we issue a "Quit" while outputting the registered pretty-printers list, the
> Python handling layer will catch it and think it's a Python error.
> 
> The fix is to check if the error coming from Python is a Quit signal. If it is,
> do not handle it as an error and resume the execution normally.

I'm not sure I fully understand this, but checking the exception
message looks suspicious to me.

It'd help if this had an accompanying testcase, to clearly show what
bug this is fixing, and make sure gdb doesn't regress in future.

We have a few tests under gdb.base/ that test pagination. Maybe
it'd be possible to copy / adjust one of those?

Also, it can't possibly be right to check msg == NULL after
having used that pointer in strncmp:

> +      if (strncmp(msg, "Quit", 5))
> +	  {
> +	    if (msg == NULL)

Thanks,
Pedro Alves
  
Tom Tromey March 15, 2016, 5:20 p.m. UTC | #2
Leonardo> Right now the "Quit" command used in the output paging is
Leonardo> handled as an exception.  If we issue a "Quit" while
Leonardo> outputting the registered pretty-printers list, the Python
Leonardo> handling layer will catch it and think it's a Python error.

Leonardo> The fix is to check if the error coming from Python is a Quit
Leonardo> signal. If it is, do not handle it as an error and resume the
Leonardo> execution normally.

I think a quit should be turned into a PyExc_KeyboardInterrupt.  So it
would make sense, IMO, to turn a PyExc_KeyboardInterrupt back into a
RETURN_QUIT in py-cmd.c.

There's a general "exception denaturation" problem in the python layer
-- that is, important information about exceptions can be lost in the
translation from gdb to python and back.  See
https://sourceware.org/bugzilla/show_bug.cgi?id=12174, though IIRC this
bug only covers one direction, while both directions matter.

Tom
  
Pedro Alves March 15, 2016, 5:51 p.m. UTC | #3
On 03/15/2016 05:20 PM, Tom Tromey wrote:
> Leonardo> Right now the "Quit" command used in the output paging is
> Leonardo> handled as an exception.  If we issue a "Quit" while
> Leonardo> outputting the registered pretty-printers list, the Python
> Leonardo> handling layer will catch it and think it's a Python error.
> 
> Leonardo> The fix is to check if the error coming from Python is a Quit
> Leonardo> signal. If it is, do not handle it as an error and resume the
> Leonardo> execution normally.
> 
> I think a quit should be turned into a PyExc_KeyboardInterrupt.  So it
> would make sense, IMO, to turn a PyExc_KeyboardInterrupt back into a
> RETURN_QUIT in py-cmd.c.

That makes sense to me.  We already do something like that, in
set_active_ext_lang / restore_active_ext_lang, actually.

(
I happen to be working on getting rid of immediate_quit, for
C++ conversion, and a good part of that is about not losing
Ctrl-C's, ever, so that feels quite apropos:

 https://github.com/palves/gdb/commits/palves/immediate_quit
)

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index af6c5cf..edcaf79 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -165,46 +165,55 @@  cmdpy_function (struct cmd_list_element *command, char *args, int from_tty)
 	 we no longer own ptype, pvalue after the call to PyErr_Restore.  */
 
       msg = gdbpy_exception_to_string (ptype, pvalue);
-      make_cleanup (xfree, msg);
-
-      if (msg == NULL)
-	{
-	  /* An error occurred computing the string representation of the
-	     error message.  This is rare, but we should inform the user.  */
-	  printf_filtered (_("An error occurred in a Python command\n"
-			     "and then another occurred computing the "
-			     "error message.\n"));
-	  gdbpy_print_stack ();
-	}
-
-      /* Don't print the stack for gdb.GdbError exceptions.
-	 It is generally used to flag user errors.
-
-	 We also don't want to print "Error occurred in Python command"
-	 for user errors.  However, a missing message for gdb.GdbError
-	 exceptions is arguably a bug, so we flag it as such.  */
-
-      if (! PyErr_GivenExceptionMatches (ptype, gdbpy_gdberror_exc)
-	  || msg == NULL || *msg == '\0')
-	{
-	  PyErr_Restore (ptype, pvalue, ptraceback);
-	  gdbpy_print_stack ();
-	  if (msg != NULL && *msg != '\0')
-	    error (_("Error occurred in Python command: %s"), msg);
+      /* We need to check this because the "Quit" command used in the output 
+         paging is handled as an exception. If we issue a "Quit" while 
+         outputting the registered pretty-printers list, the Python handling 
+         layer will catch it and think it's a Python error                 */
+      if (strncmp(msg, "Quit", 5))
+	  {
+	    if (msg == NULL)
+	      {
+		/* An error occurred computing the string representation of the
+		   error message.  This is rare, but we should inform the user.*/
+		printf_filtered (_("An error occurred in a Python command\n"
+				   "and then another occurred computing the "
+				   "error message.\n"));
+		gdbpy_print_stack ();
+	      }
+
+	/* Don't print the stack for gdb.GdbError exceptions.
+	   It is generally used to flag user errors.
+
+	   We also don't want to print "Error occurred in Python command"
+	   for user errors.  However, a missing message for gdb.GdbError
+	   exceptions is arguably a bug, so we flag it as such.  */
+
+	  if (! PyErr_GivenExceptionMatches (ptype, gdbpy_gdberror_exc)
+	      || msg == NULL || *msg == '\0')
+	    {
+	      PyErr_Restore (ptype, pvalue, ptraceback);
+	      gdbpy_print_stack ();
+	      if (msg != NULL && *msg != '\0')
+	        error (_("Error occurred in Python command: %s"), msg);
+	      else
+	        error (_("Error occurred in Python command."));
+	    }
 	  else
-	    error (_("Error occurred in Python command."));
-	}
-      else
-	{
-	  Py_XDECREF (ptype);
-	  Py_XDECREF (pvalue);
-	  Py_XDECREF (ptraceback);
-	  error ("%s", msg);
-	}
-    }
+	    {
+	      Py_XDECREF (ptype);
+	      Py_XDECREF (pvalue);
+	      Py_XDECREF (ptraceback);
+	      error ("%s", msg);
+	    }
+	} // ELSE: This was not an error just quit signal. Do nothing.
 
-  Py_DECREF (result);
-  do_cleanups (cleanup);
+      make_cleanup (xfree, msg);
+    }
+  else
+    {
+      Py_DECREF (result);
+      do_cleanups (cleanup);
+    }
 }
 
 /* Helper function for the Python command completers (both "pure"