Use a wrapper for PyErr_Fetch

This introduces a new class that wraps PyErr_Fetch and PyErr_Restore,
and then changes all the callers in gdb to use it.  This reduces the
amount of explicit reference counting that is done in the Python code.
I also found and fixed a latent bug in gdbpy_print_stack -- it was not
correctly checking some error conditions, nor clearing the exception
when needed.

gdb/ChangeLog
2019-01-03  Tom Tromey  <tom@tromey.com>

	* python/python.c (gdbpy_enter, ~gdbpy_enter): Update.
	(gdbpy_print_stack): Use gdbpy_err_fetch.
	* python/python-internal.h (class gdbpy_err_fetch): New class.
	(class gdbpy_enter) <m_error_type, m_error_value,
	m_error_traceback>: Remove.
	<m_error>: New member.
	(gdbpy_exception_to_string): Don't declare.
	* python/py-varobj.c (py_varobj_iter_next): Use gdbpy_err_fetch.
	* python/py-value.c (convert_value_from_python): Use
	gdbpy_err_fetch.
	* python/py-utils.c (gdbpy_err_fetch::to_string): Rename from
	gdbpy_exception_to_string.
	(gdbpy_handle_exception): Use gdbpy_err_fetch.
	* python/py-prettyprint.c (print_stack_unless_memory_error): Use
	gdbpy_err_fetch.
This commit is contained in:
Tom Tromey 2018-12-27 11:32:01 -07:00
parent 169bb27bce
commit 5c329e6ab4
7 changed files with 121 additions and 73 deletions

View file

@ -203,28 +203,33 @@ gdbpy_obj_to_string (PyObject *obj)
return NULL;
}
/* Return the string representation of the exception represented by
TYPE, VALUE which is assumed to have been obtained with PyErr_Fetch,
i.e., the error indicator is currently clear.
If the result is NULL a python error occurred, the caller must clear it. */
/* See python-internal.h. */
gdb::unique_xmalloc_ptr<char>
gdbpy_exception_to_string (PyObject *ptype, PyObject *pvalue)
gdbpy_err_fetch::to_string () const
{
/* There are a few cases to consider.
For example:
pvalue is a string when PyErr_SetString is used.
pvalue is not a string when raise "foo" is used, instead it is None
and ptype is "foo".
So the algorithm we use is to print `str (pvalue)' if it's not
None, otherwise we print `str (ptype)'.
value is a string when PyErr_SetString is used.
value is not a string when raise "foo" is used, instead it is None
and type is "foo".
So the algorithm we use is to print `str (value)' if it's not
None, otherwise we print `str (type)'.
Using str (aka PyObject_Str) will fetch the error message from
gdb.GdbError ("message"). */
if (pvalue && pvalue != Py_None)
return gdbpy_obj_to_string (pvalue);
if (m_error_value && m_error_value != Py_None)
return gdbpy_obj_to_string (m_error_value);
else
return gdbpy_obj_to_string (ptype);
return gdbpy_obj_to_string (m_error_type);
}
/* See python-internal.h. */
gdb::unique_xmalloc_ptr<char>
gdbpy_err_fetch::type_to_string () const
{
return gdbpy_obj_to_string (m_error_type);
}
/* Convert a GDB exception to the appropriate Python exception.
@ -394,16 +399,8 @@ gdb_pymodule_addobject (PyObject *module, const char *name, PyObject *object)
void
gdbpy_handle_exception ()
{
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch (&ptype, &pvalue, &ptraceback);
/* Try to fetch an error message contained within ptype, pvalue.
When fetching the error message we need to make our own copy,
we no longer own ptype, pvalue after the call to PyErr_Restore. */
gdb::unique_xmalloc_ptr<char>
msg (gdbpy_exception_to_string (ptype, pvalue));
gdbpy_err_fetch fetched_error;
gdb::unique_xmalloc_ptr<char> msg = fetched_error.to_string ();
if (msg == NULL)
{
@ -422,12 +419,12 @@ gdbpy_handle_exception ()
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, PyExc_KeyboardInterrupt))
if (fetched_error.type_matches (PyExc_KeyboardInterrupt))
throw_quit ("Quit");
else if (! PyErr_GivenExceptionMatches (ptype, gdbpy_gdberror_exc)
|| msg == NULL || *msg == '\0')
else if (! fetched_error.type_matches (gdbpy_gdberror_exc)
|| msg == NULL || *msg == '\0')
{
PyErr_Restore (ptype, pvalue, ptraceback);
fetched_error.restore ();
gdbpy_print_stack ();
if (msg != NULL && *msg != '\0')
error (_("Error occurred in Python: %s"), msg.get ());
@ -435,10 +432,5 @@ gdbpy_handle_exception ()
error (_("Error occurred in Python."));
}
else
{
Py_XDECREF (ptype);
Py_XDECREF (pvalue);
Py_XDECREF (ptraceback);
error ("%s", msg.get ());
}
error ("%s", msg.get ());
}