This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA 10/11] Use gdbpy_ref in py-prettyprint.c


>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> This changes some spots in py-prettyprint.c to use gdbpy_ref.
Tom> 2016-11-12  Tom Tromey  <tom@tromey.com>
Tom> 	* python/py-prettyprint.c (print_stack_unless_memory_error)
Tom> 	(print_string_repr, print_children): Use gdbpy_ref.

The buildbot revealed that this patch had some problems.  I had failed
to notice that push_dummy_python_frame, a subroutine of print_children,
created a cleanup that had to be run by the caller.  This code path is
only used by Python 2, which is why I didn't see it in my local testing.
(I usually build only against Python 3, but curiously the buildbot only
seems to build against Python 2.)

This updated patch rewrites push_dummy_python_frame to be a class that
handles the necessary cleanup in its destructor.

I've tested this on x86-64 Fedora 24 using both Python 2 and Python 3.

I think the patch has changed enough to require re-review.

Tom

commit 5d7057c317feab7ed4788d1531190ac4fbc8b160
Author: Tom Tromey <tom@tromey.com>
Date:   Sat Nov 12 12:07:16 2016 -0700

    Use gdbpy_ref in py-prettyprint.c
    
    This changes some spots in py-prettyprint.c to use gdbpy_ref.  It also
    changes push_dummy_python_frame to be a class, rather than having it
    create a cleanup.
    
    2016-11-12  Tom Tromey  <tom@tromey.com>
    
    	* python/py-prettyprint.c (print_stack_unless_memory_error)
    	(print_string_repr, print_children): Use gdbpy_ref.
    	(dummy_python_frame): New class.
    	(dummy_python_frame::dummy_python_frame): Rename from
    	push_dummy_python_frame.
    	(py_restore_tstate): Remove.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5947b50..2525ac7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2016-11-12  Tom Tromey  <tom@tromey.com>
 
+	* python/py-prettyprint.c (print_stack_unless_memory_error)
+	(print_string_repr, print_children): Use gdbpy_ref.
+	(dummy_python_frame): New class.
+	(dummy_python_frame::dummy_python_frame): Rename from
+	push_dummy_python_frame.
+	(py_restore_tstate): Remove.
+
+2016-11-12  Tom Tromey  <tom@tromey.com>
+
 	* python/py-framefilter.c (py_print_frame): Use gdbpy_ref.
 
 2016-11-12  Tom Tromey  <tom@tromey.com>
diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c
index e7a3e76..8c3d24a 100644
--- a/gdb/python/py-prettyprint.c
+++ b/gdb/python/py-prettyprint.c
@@ -252,13 +252,13 @@ print_stack_unless_memory_error (struct ui_file *stream)
 {
   if (PyErr_ExceptionMatches (gdbpy_gdb_memory_error))
     {
-      struct cleanup *cleanup;
       PyObject *type, *value, *trace;
 
       PyErr_Fetch (&type, &value, &trace);
-      cleanup = make_cleanup_py_decref (type);
-      make_cleanup_py_decref (value);
-      make_cleanup_py_decref (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));
@@ -268,8 +268,6 @@ print_stack_unless_memory_error (struct ui_file *stream)
       else
 	fprintf_filtered (stream, _("<error reading variable: %s>"),
 			  msg.get ());
-
-      do_cleanups (cleanup);
     }
   else
     gdbpy_print_stack ();
@@ -286,17 +284,14 @@ print_string_repr (PyObject *printer, const char *hint,
 		   struct gdbarch *gdbarch)
 {
   struct value *replacement = NULL;
-  PyObject *py_str = NULL;
   enum string_repr_result result = string_repr_ok;
 
-  py_str = pretty_print_one_value (printer, &replacement);
-  if (py_str)
+  gdbpy_ref py_str (pretty_print_one_value (printer, &replacement));
+  if (py_str != NULL)
     {
-      struct cleanup *cleanup = make_cleanup_py_decref (py_str);
-
       if (py_str == Py_None)
 	result = string_repr_none;
-      else if (gdbpy_is_lazy_string (py_str))
+      else if (gdbpy_is_lazy_string (py_str.get ()))
 	{
 	  CORE_ADDR addr;
 	  long length;
@@ -304,7 +299,7 @@ print_string_repr (PyObject *printer, const char *hint,
 	  gdb::unique_xmalloc_ptr<char> encoding;
 	  struct value_print_options local_opts = *options;
 
-	  gdbpy_extract_lazy_string (py_str, &addr, &type,
+	  gdbpy_extract_lazy_string (py_str.get (), &addr, &type,
 				     &length, &encoding);
 
 	  local_opts.addressprint = 0;
@@ -313,22 +308,20 @@ print_string_repr (PyObject *printer, const char *hint,
 	}
       else
 	{
-	  PyObject *string;
-
-	  string = python_string_to_target_python_string (py_str);
-	  if (string)
+	  gdbpy_ref string
+	    (python_string_to_target_python_string (py_str.get ()));
+	  if (string != NULL)
 	    {
 	      char *output;
 	      long length;
 	      struct type *type;
 
-	      make_cleanup_py_decref (string);
 #ifdef IS_PY3K
-	      output = PyBytes_AS_STRING (string);
-	      length = PyBytes_GET_SIZE (string);
+	      output = PyBytes_AS_STRING (string.get ());
+	      length = PyBytes_GET_SIZE (string.get ());
 #else
-	      output = PyString_AsString (string);
-	      length = PyString_Size (string);
+	      output = PyString_AsString (string.get ());
+	      length = PyString_Size (string.get ());
 #endif
 	      type = builtin_type (gdbarch)->builtin_char;
 
@@ -344,8 +337,6 @@ print_string_repr (PyObject *printer, const char *hint,
 	      print_stack_unless_memory_error (stream);
 	    }
 	}
-
-      do_cleanups (cleanup);
     }
   else if (replacement)
     {
@@ -364,80 +355,84 @@ print_string_repr (PyObject *printer, const char *hint,
 }
 
 #ifndef IS_PY3K
-static void
-py_restore_tstate (void *p)
-{
-  PyFrameObject *frame = (PyFrameObject *) p;
-  PyThreadState *tstate = PyThreadState_GET ();
-
-  tstate->frame = frame;
-}
 
 /* Create a dummy PyFrameObject, needed to work around
    a Python-2.4 bug with generators.  */
-static PyObject *
-push_dummy_python_frame (void)
+class dummy_python_frame
 {
-  PyObject *empty_string, *null_tuple, *globals;
-  PyCodeObject *code;
-  PyFrameObject *frame;
-  PyThreadState *tstate;
+ public:
 
-  empty_string = PyString_FromString ("");
-  if (!empty_string)
-    return NULL;
+  dummy_python_frame ();
 
-  null_tuple = PyTuple_New (0);
-  if (!null_tuple)
-    {
-      Py_DECREF (empty_string);
-      return NULL;
-    }
+  ~dummy_python_frame ()
+  {
+    if (m_valid)
+      m_tstate->frame = m_saved_frame;
+  }
 
-  code = PyCode_New (0,			/* argcount */
-		     0,			/* nlocals */
-		     0,			/* stacksize */
-		     0,			/* flags */
-		     empty_string,	/* code */
-		     null_tuple,	/* consts */
-		     null_tuple,	/* names */
-		     null_tuple,	/* varnames */
-#if PYTHON_API_VERSION >= 1010
-		     null_tuple,	/* freevars */
-		     null_tuple,	/* cellvars */
-#endif
-		     empty_string,	/* filename */
-		     empty_string,	/* name */
-		     1,			/* firstlineno */
-		     empty_string	/* lnotab */
-		    );
+  bool failed () const
+  {
+    return !m_valid;
+  }
 
-  Py_DECREF (empty_string);
-  Py_DECREF (null_tuple);
+ private:
 
-  if (!code)
-    return NULL;
+  bool m_valid;
+  PyFrameObject *m_saved_frame;
+  gdbpy_ref m_frame;
+  PyThreadState *m_tstate;
+};
 
-  globals = PyDict_New ();
-  if (!globals)
-    {
-      Py_DECREF (code);
-      return NULL;
-    }
+dummy_python_frame::dummy_python_frame ()
+: m_valid (false),
+  m_saved_frame (NULL),
+  m_tstate (NULL)
+{
+  PyCodeObject *code;
+  PyFrameObject *frame;
 
-  tstate = PyThreadState_GET ();
+  gdbpy_ref empty_string (PyString_FromString (""));
+  if (empty_string == NULL)
+    return;
 
-  frame = PyFrame_New (tstate, code, globals, NULL);
+  gdbpy_ref null_tuple (PyTuple_New (0));
+  if (null_tuple == NULL)
+    return;
 
-  Py_DECREF (globals);
-  Py_DECREF (code);
+  code = PyCode_New (0,			  /* argcount */
+		     0,			  /* locals */
+		     0,			  /* stacksize */
+		     0,			  /* flags */
+		     empty_string.get (), /* code */
+		     null_tuple.get (),	  /* consts */
+		     null_tuple.get (),	  /* names */
+		     null_tuple.get (),	  /* varnames */
+#if PYTHON_API_VERSION >= 1010
+		     null_tuple.get (),	  /* freevars */
+		     null_tuple.get (),	  /* cellvars */
+#endif
+		     empty_string.get (), /* filename */
+		     empty_string.get (), /* name */
+		     1,			  /* firstlineno */
+		     empty_string.get ()  /* lnotab */
+		     );
+  if (code == NULL)
+    return;
+  gdbpy_ref code_holder ((PyObject *) code);
 
-  if (!frame)
-    return NULL;
+  gdbpy_ref globals (PyDict_New ());
+  if (globals == NULL)
+    return;
+
+  m_tstate = PyThreadState_GET ();
+  frame = PyFrame_New (m_tstate, code, globals.get (), NULL);
+  if (frame == NULL)
+    return;
 
-  tstate->frame = frame;
-  make_cleanup (py_restore_tstate, frame->f_back);
-  return (PyObject *) frame;
+  m_frame.reset ((PyObject *) frame);
+  m_tstate->frame = frame;
+  m_saved_frame = frame->f_back;
+  m_valid = true;
 }
 #endif
 
@@ -453,11 +448,6 @@ print_children (PyObject *printer, const char *hint,
 {
   int is_map, is_array, done_flag, pretty;
   unsigned int i;
-  PyObject *children, *iter;
-#ifndef IS_PY3K
-  PyObject *frame;
-#endif
-  struct cleanup *cleanups;
 
   if (! PyObject_HasAttr (printer, gdbpy_children_cst))
     return;
@@ -467,23 +457,20 @@ print_children (PyObject *printer, const char *hint,
   is_map = hint && ! strcmp (hint, "map");
   is_array = hint && ! strcmp (hint, "array");
 
-  children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
-					 NULL);
-  if (! children)
+  gdbpy_ref children (PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
+						  NULL));
+  if (children == NULL)
     {
       print_stack_unless_memory_error (stream);
       return;
     }
 
-  cleanups = make_cleanup_py_decref (children);
-
-  iter = PyObject_GetIter (children);
-  if (!iter)
+  gdbpy_ref iter (PyObject_GetIter (children.get ()));
+  if (iter == NULL)
     {
       print_stack_unless_memory_error (stream);
-      goto done;
+      return;
     }
-  make_cleanup_py_decref (iter);
 
   /* Use the prettyformat_arrays option if we are printing an array,
      and the pretty option otherwise.  */
@@ -501,23 +488,22 @@ print_children (PyObject *printer, const char *hint,
      where it insists on having a non-NULL tstate->frame when
      a generator is called.  */
 #ifndef IS_PY3K
-  frame = push_dummy_python_frame ();
-  if (!frame)
+  dummy_python_frame frame;
+  if (frame.failed ())
     {
       gdbpy_print_stack ();
-      goto done;
+      return;
     }
-  make_cleanup_py_decref (frame);
 #endif
 
   done_flag = 0;
   for (i = 0; i < options->print_max; ++i)
     {
-      PyObject *py_v, *item = PyIter_Next (iter);
+      PyObject *py_v;
       const char *name;
-      struct cleanup *inner_cleanup;
 
-      if (! item)
+      gdbpy_ref item (PyIter_Next (iter.get ()));
+      if (item == NULL)
 	{
 	  if (PyErr_Occurred ())
 	    print_stack_unless_memory_error (stream);
@@ -528,16 +514,15 @@ print_children (PyObject *printer, const char *hint,
 	  break;
 	}
 
-      if (! PyTuple_Check (item) || PyTuple_Size (item) != 2)
+      if (! PyTuple_Check (item.get ()) || PyTuple_Size (item.get ()) != 2)
 	{
 	  PyErr_SetString (PyExc_TypeError,
 			   _("Result of children iterator not a tuple"
 			     " of two elements."));
 	  gdbpy_print_stack ();
-	  Py_DECREF (item);
 	  continue;
 	}
-      if (! PyArg_ParseTuple (item, "sO", &name, &py_v))
+      if (! PyArg_ParseTuple (item.get (), "sO", &name, &py_v))
 	{
 	  /* The user won't necessarily get a stack trace here, so provide
 	     more context.  */
@@ -545,10 +530,8 @@ print_children (PyObject *printer, const char *hint,
 	    fprintf_unfiltered (gdb_stderr,
 				_("Bad result from children iterator.\n"));
 	  gdbpy_print_stack ();
-	  Py_DECREF (item);
 	  continue;
 	}
-      inner_cleanup = make_cleanup_py_decref (item);
 
       /* Print initial "{".  For other elements, there are three
 	 cases:
@@ -643,8 +626,6 @@ print_children (PyObject *printer, const char *hint,
 
       if (is_map && i % 2 == 0)
 	fputs_filtered ("] = ", stream);
-
-      do_cleanups (inner_cleanup);
     }
 
   if (i)
@@ -665,9 +646,6 @@ print_children (PyObject *printer, const char *hint,
 	}
       fputs_filtered ("}", stream);
     }
-
- done:
-  do_cleanups (cleanups);
 }
 
 enum ext_lang_rc


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]