[PING] Python: Fix Python error when "Quit"ting a paged info pretty-printers
Commit Message
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
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
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
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
@@ -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"