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:
parent
169bb27bce
commit
5c329e6ab4
@ -1,3 +1,21 @@
|
||||
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.
|
||||
|
||||
2019-01-03 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* linux-nat.c (delete_lwp_cleanup): Delete.
|
||||
|
@ -259,16 +259,8 @@ print_stack_unless_memory_error (struct ui_file *stream)
|
||||
{
|
||||
if (PyErr_ExceptionMatches (gdbpy_gdb_memory_error))
|
||||
{
|
||||
PyObject *type, *value, *trace;
|
||||
|
||||
PyErr_Fetch (&type, &value, &trace);
|
||||
|
||||
gdbpy_ref<> type_ref (type);
|
||||
gdbpy_ref<> value_ref (value);
|
||||
gdbpy_ref<> trace_ref (trace);
|
||||
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
msg (gdbpy_exception_to_string (type, value));
|
||||
gdbpy_err_fetch fetched_error;
|
||||
gdb::unique_xmalloc_ptr<char> msg = fetched_error.to_string ();
|
||||
|
||||
if (msg == NULL || *msg == '\0')
|
||||
fprintf_filtered (stream, _("<error reading variable>"));
|
||||
|
@ -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 ());
|
||||
}
|
||||
|
@ -1661,9 +1661,7 @@ convert_value_from_python (PyObject *obj)
|
||||
ULONGEST instead. */
|
||||
if (PyErr_ExceptionMatches (PyExc_OverflowError))
|
||||
{
|
||||
PyObject *etype, *evalue, *etraceback;
|
||||
|
||||
PyErr_Fetch (&etype, &evalue, &etraceback);
|
||||
gdbpy_err_fetch fetched_error;
|
||||
gdbpy_ref<> zero (PyInt_FromLong (0));
|
||||
|
||||
/* Check whether obj is positive. */
|
||||
@ -1676,8 +1674,10 @@ convert_value_from_python (PyObject *obj)
|
||||
value = value_from_ulongest (builtin_type_upylong, ul);
|
||||
}
|
||||
else
|
||||
/* There's nothing we can do. */
|
||||
PyErr_Restore (etype, evalue, etraceback);
|
||||
{
|
||||
/* There's nothing we can do. */
|
||||
fetched_error.restore ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -70,14 +70,8 @@ py_varobj_iter_next (struct varobj_iter *self)
|
||||
/* If we got a memory error, just use the text as the item. */
|
||||
if (PyErr_ExceptionMatches (gdbpy_gdb_memory_error))
|
||||
{
|
||||
PyObject *type, *value, *trace;
|
||||
|
||||
PyErr_Fetch (&type, &value, &trace);
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
value_str (gdbpy_exception_to_string (type, value));
|
||||
Py_XDECREF (type);
|
||||
Py_XDECREF (value);
|
||||
Py_XDECREF (trace);
|
||||
gdbpy_err_fetch fetched_error;
|
||||
gdb::unique_xmalloc_ptr<char> value_str = fetched_error.to_string ();
|
||||
if (value_str == NULL)
|
||||
{
|
||||
gdbpy_print_stack ();
|
||||
|
@ -591,6 +591,60 @@ int gdbpy_initialize_xmethods (void)
|
||||
int gdbpy_initialize_unwind (void)
|
||||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
|
||||
/* A wrapper for PyErr_Fetch that handles reference counting for the
|
||||
caller. */
|
||||
class gdbpy_err_fetch
|
||||
{
|
||||
public:
|
||||
|
||||
gdbpy_err_fetch ()
|
||||
{
|
||||
PyErr_Fetch (&m_error_type, &m_error_value, &m_error_traceback);
|
||||
}
|
||||
|
||||
~gdbpy_err_fetch ()
|
||||
{
|
||||
Py_XDECREF (m_error_type);
|
||||
Py_XDECREF (m_error_value);
|
||||
Py_XDECREF (m_error_traceback);
|
||||
}
|
||||
|
||||
/* Call PyErr_Restore using the values stashed in this object.
|
||||
After this call, this object is invalid and neither the to_string
|
||||
nor restore methods may be used again. */
|
||||
|
||||
void restore ()
|
||||
{
|
||||
PyErr_Restore (m_error_type, m_error_value, m_error_traceback);
|
||||
m_error_type = nullptr;
|
||||
m_error_value = nullptr;
|
||||
m_error_traceback = nullptr;
|
||||
}
|
||||
|
||||
/* Return the string representation of the exception represented by
|
||||
this object. If the result is NULL a python error occurred, the
|
||||
caller must clear it. */
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> to_string () const;
|
||||
|
||||
/* Return the string representation of the type of the exception
|
||||
represented by this object. If the result is NULL a python error
|
||||
occurred, the caller must clear it. */
|
||||
|
||||
gdb::unique_xmalloc_ptr<char> type_to_string () const;
|
||||
|
||||
/* Return true if the stored type matches TYPE, false otherwise. */
|
||||
|
||||
bool type_matches (PyObject *type) const
|
||||
{
|
||||
return PyErr_GivenExceptionMatches (m_error_type, type);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PyObject *m_error_type, *m_error_value, *m_error_traceback;
|
||||
};
|
||||
|
||||
/* Called before entering the Python interpreter to install the
|
||||
current language and architecture to be used for Python values.
|
||||
Also set the active extension language for GDB so that SIGINT's
|
||||
@ -612,7 +666,10 @@ class gdbpy_enter
|
||||
PyGILState_STATE m_state;
|
||||
struct gdbarch *m_gdbarch;
|
||||
const struct language_defn *m_language;
|
||||
PyObject *m_error_type, *m_error_value, *m_error_traceback;
|
||||
|
||||
/* An optional is used here because we don't want to call
|
||||
PyErr_Fetch too early. */
|
||||
gdb::optional<gdbpy_err_fetch> m_error;
|
||||
};
|
||||
|
||||
/* Like gdbpy_enter, but takes a varobj. This is a subclass just to
|
||||
@ -665,8 +722,6 @@ gdb::unique_xmalloc_ptr<char> python_string_to_host_string (PyObject *obj);
|
||||
gdbpy_ref<> host_string_to_python_string (const char *str);
|
||||
int gdbpy_is_string (PyObject *obj);
|
||||
gdb::unique_xmalloc_ptr<char> gdbpy_obj_to_string (PyObject *obj);
|
||||
gdb::unique_xmalloc_ptr<char> gdbpy_exception_to_string (PyObject *ptype,
|
||||
PyObject *pvalue);
|
||||
|
||||
int gdbpy_is_lazy_string (PyObject *result);
|
||||
void gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
|
||||
|
@ -214,7 +214,7 @@ gdbpy_enter::gdbpy_enter (struct gdbarch *gdbarch,
|
||||
python_language = language;
|
||||
|
||||
/* Save it and ensure ! PyErr_Occurred () afterwards. */
|
||||
PyErr_Fetch (&m_error_type, &m_error_value, &m_error_traceback);
|
||||
m_error.emplace ();
|
||||
}
|
||||
|
||||
gdbpy_enter::~gdbpy_enter ()
|
||||
@ -227,7 +227,7 @@ gdbpy_enter::~gdbpy_enter ()
|
||||
warning (_("internal error: Unhandled Python exception"));
|
||||
}
|
||||
|
||||
PyErr_Restore (m_error_type, m_error_value, m_error_traceback);
|
||||
m_error->restore ();
|
||||
|
||||
PyGILState_Release (m_state);
|
||||
python_gdbarch = m_gdbarch;
|
||||
@ -1234,24 +1234,25 @@ gdbpy_print_stack (void)
|
||||
/* Print "message", just error print message. */
|
||||
else
|
||||
{
|
||||
PyObject *ptype, *pvalue, *ptraceback;
|
||||
gdbpy_err_fetch fetched_error;
|
||||
|
||||
PyErr_Fetch (&ptype, &pvalue, &ptraceback);
|
||||
|
||||
/* Fetch the error message contained within ptype, pvalue. */
|
||||
gdb::unique_xmalloc_ptr<char>
|
||||
msg (gdbpy_exception_to_string (ptype, pvalue));
|
||||
gdb::unique_xmalloc_ptr<char> type (gdbpy_obj_to_string (ptype));
|
||||
gdb::unique_xmalloc_ptr<char> msg = fetched_error.to_string ();
|
||||
gdb::unique_xmalloc_ptr<char> type;
|
||||
/* Don't compute TYPE if MSG already indicates that there is an
|
||||
error. */
|
||||
if (msg != NULL)
|
||||
type = fetched_error.type_to_string ();
|
||||
|
||||
TRY
|
||||
{
|
||||
if (msg == NULL)
|
||||
if (msg == NULL || type == NULL)
|
||||
{
|
||||
/* An error occurred computing the string representation of the
|
||||
error message. */
|
||||
fprintf_filtered (gdb_stderr,
|
||||
_("Error occurred computing Python error" \
|
||||
"message.\n"));
|
||||
PyErr_Clear ();
|
||||
}
|
||||
else
|
||||
fprintf_filtered (gdb_stderr, "Python Exception %s %s: \n",
|
||||
@ -1261,10 +1262,6 @@ gdbpy_print_stack (void)
|
||||
{
|
||||
}
|
||||
END_CATCH
|
||||
|
||||
Py_XDECREF (ptype);
|
||||
Py_XDECREF (pvalue);
|
||||
Py_XDECREF (ptraceback);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user