[Zodb-checkins] CVS: StandaloneZODB/BTrees - BucketTemplate.c:1.20

Jeremy Hylton jeremy@zope.com
Wed, 31 Oct 2001 14:19:38 -0500


Update of /cvs-repository/StandaloneZODB/BTrees
In directory cvs.zope.org:/tmp/cvs-serv31096

Modified Files:
	BucketTemplate.c 
Log Message:
Fix memory leak in BTrees.

The Mapping_update() method iterated over a sequence of 2-tuples, but
held an extra reference to the sequence.  The sequence object was
DECREFed on an error exit but not on the normal return.

The fix reworks the control flow of the function to make the reference
counting behavior a little clearer:

   - Test for call with no arguments and return immediately if so.

   - If the argument is a sequence, don't INCREF it.  

   - If the argument passed isn't a sequence, call its items() method
     and store the result in the local variables seq and items.

   - On exit, do Py_XDECREF(items).  This will do a decref only if a
     the second case above applied.

Two other minor nits:

   - Make consistent use of spaces around = in assignments (as opposed
     to a fix of both)

   - Remove assignment from conditional expression.



=== StandaloneZODB/BTrees/BucketTemplate.c 1.19 => 1.20 ===
 }
 
+/**
+ ** Mapping_update()
+ **
+ ** Accepts a sequence of 2-tuples or any object with an items()
+ ** method that returns a sequence of 2-tuples.
+ **
+ */
+
 static PyObject *
 Mapping_update(PyObject *self, PyObject *args)
 {
-  PyObject *seq=0, *o, *t, *v, *tb, *k;
+  PyObject *seq=0, *o, *t, *v, *tb, *k, *items = NULL;
   int i, ind;
 
   UNLESS(PyArg_ParseTuple(args, "|O:update", &seq)) return NULL;
 
-  if (seq)
+  if (!seq)
+    {
+      Py_INCREF(Py_None);
+      return Py_None;
+    }
+    
+  if (!PySequence_Check(seq))
     {
+      items = PyObject_GetAttr(seq, items_str);
+      UNLESS(items) return NULL;
+      ASSIGN(items, PyObject_CallObject(items, NULL));
+      UNLESS(items) return NULL;
+      /* items is DECREFed on exit, seq is not */
+      seq = items;
+    }
 
-      if (PySequence_Check(seq))
-        {
-          Py_INCREF(seq);
-        }
+  for (i=0; ; i++)
+    {
+      o = PySequence_GetItem(seq, i);
+      UNLESS (o)
+	{
+	  PyErr_Fetch(&t, &v, &tb);
+	  if (t != PyExc_IndexError)
+	    {
+	      PyErr_Restore(t, v, tb);
+	      goto err;
+	    }
+	  Py_XDECREF(t);
+	  Py_XDECREF(v);
+	  Py_XDECREF(tb);
+	  break;
+	}
+      ind = PyArg_ParseTuple(o, "OO;items must be 2-item tuples", &k, &v);
+      if (ind)
+	ind = PyObject_SetItem(self, k, v);
       else
-        {
-          seq=PyObject_GetAttr(seq, items_str);
-          UNLESS(seq) return NULL;
-          ASSIGN(seq, PyObject_CallObject(seq, NULL));
-          UNLESS(seq) return NULL;
-        }
-
-      for (i=0; ; i++)
-        {
-          UNLESS (o=PySequence_GetItem(seq, i))
-            {
-              PyErr_Fetch(&t, &v, &tb);
-              if (t != PyExc_IndexError)
-                {
-                  PyErr_Restore(t, v, tb);
-                  goto err;
-                }
-              Py_XDECREF(t);
-              Py_XDECREF(v);
-              Py_XDECREF(tb);
-              break;
-            }
-          ind=PyArg_ParseTuple(o, "OO;items must be 2-item tuples", &k, &v);
-          if (ind)
-            ind = PyObject_SetItem(self, k, v);
-          else
-            ind=-1;
-          Py_DECREF(o);
-          if (ind < 0) goto err;
-        }
+	ind = -1;
+      Py_DECREF(o);
+      if (ind < 0) goto err;
     }
 
+  Py_XDECREF(items);
   Py_INCREF(Py_None);
   return Py_None;
 
  err:
-  Py_DECREF(seq);
+  Py_XDECREF(items);
   return NULL;
 }