[Python-checkins] python/dist/src/Modules _bsddb.c,1.31,1.32

greg at users.sourceforge.net greg at users.sourceforge.net
Sun Jun 27 19:32:36 EDT 2004


Update of /cvsroot/python/python/dist/src/Modules
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32305/Modules

Modified Files:
	_bsddb.c 
Log Message:
SF patch / bug #967763
Fix memory leaks revealed by valgrind and ensuing code inspection.

In the existing test suite valgrind revealed two memory leaks (DB_get
and DBC_set_range).  Code inspection revealed that there were many other
potential similar leaks (many on odd code error paths such as passing
something other than a DBTxn object for a txn= parameter or in the face
of an out of memory error).  The most common case that would cause a
leak was when using recno or queue format databases with integer keys,
sometimes only with an exception exit.


Index: _bsddb.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/_bsddb.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -C2 -d -r1.31 -r1.32
*** _bsddb.c	25 Mar 2004 02:16:22 -0000	1.31
--- _bsddb.c	27 Jun 2004 23:32:33 -0000	1.32
***************
*** 298,302 ****
  
  #define FREE_DBT(dbt)               if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \
!                                          dbt.data != NULL) { free(dbt.data); }
  
  
--- 298,302 ----
  
  #define FREE_DBT(dbt)               if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \
!                                          dbt.data != NULL) { free(dbt.data); dbt.data = NULL; }
  
  
***************
*** 331,335 ****
      else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) {
          PyErr_SetString(PyExc_TypeError,
!                         "Key and Data values must be of type string or None.");
          return 0;
      }
--- 331,335 ----
      else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) {
          PyErr_SetString(PyExc_TypeError,
!                         "Data values must be of type string or None.");
          return 0;
      }
***************
*** 341,345 ****
     what's been given, verifies that it's allowed, and then makes the DBT.
  
!    Caller should call FREE_DBT(key) when done. */
  static int
  make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
--- 341,345 ----
     what's been given, verifies that it's allowed, and then makes the DBT.
  
!    Caller MUST call FREE_DBT(key) when done. */
  static int
  make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
***************
*** 1299,1307 ****
      if (!make_key_dbt(self, keyobj, &key, NULL))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn))
          return NULL;
  
!     if (-1 == _DB_delete(self, txn, &key, 0))
          return NULL;
  
      FREE_DBT(key);
--- 1299,1311 ----
      if (!make_key_dbt(self, keyobj, &key, NULL))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
!     if (-1 == _DB_delete(self, txn, &key, 0)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      FREE_DBT(key);
***************
*** 1349,1354 ****
      if (!make_key_dbt(self, keyobj, &key, &flags))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn))
          return NULL;
  
      CLEAR_DBT(data);
--- 1353,1360 ----
      if (!make_key_dbt(self, keyobj, &key, &flags))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      CLEAR_DBT(data);
***************
*** 1357,1362 ****
          data.flags = DB_DBT_MALLOC;
      }
!     if (!add_partial_dbt(&data, dlen, doff))
          return NULL;
  
      MYDB_BEGIN_ALLOW_THREADS;
--- 1363,1370 ----
          data.flags = DB_DBT_MALLOC;
      }
!     if (!add_partial_dbt(&data, dlen, doff)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      MYDB_BEGIN_ALLOW_THREADS;
***************
*** 1380,1386 ****
          else /* return just the data */
              retval = PyString_FromStringAndSize((char*)data.data, data.size);
-         FREE_DBT(key);
          FREE_DBT(data);
      }
  
      RETURN_IF_ERR();
--- 1388,1394 ----
          else /* return just the data */
              retval = PyString_FromStringAndSize((char*)data.data, data.size);
          FREE_DBT(data);
      }
+     FREE_DBT(key);
  
      RETURN_IF_ERR();
***************
*** 1407,1412 ****
      if (!make_key_dbt(self, keyobj, &key, &flags))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn))
          return NULL;
      CLEAR_DBT(data);
  
--- 1415,1422 ----
      if (!make_key_dbt(self, keyobj, &key, &flags))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn)) {
!         FREE_DBT(key);
          return NULL;
+     }
      CLEAR_DBT(data);
  
***************
*** 1450,1457 ****
      if (!make_key_dbt(self, keyobj, &key, NULL))
          return NULL;
!     if (!make_dbt(dataobj, &data))
!         return NULL;
!     if (!checkTxnObj(txnobj, &txn))
          return NULL;
  
      flags |= DB_GET_BOTH;
--- 1460,1469 ----
      if (!make_key_dbt(self, keyobj, &key, NULL))
          return NULL;
!     if ( !make_dbt(dataobj, &data) ||
!          !checkTxnObj(txnobj, &txn) )
!     {
!         FREE_DBT(key);
          return NULL;
+     }
  
      flags |= DB_GET_BOTH;
***************
*** 1720,1727 ****
  
      CHECK_DB_NOT_CLOSED(self);
!     if (!make_key_dbt(self, keyobj, &key, NULL)) return NULL;
!     if (!make_dbt(dataobj, &data)) return NULL;
!     if (!add_partial_dbt(&data, dlen, doff)) return NULL;
!     if (!checkTxnObj(txnobj, &txn)) return NULL;
  
      if (-1 == _DB_put(self, txn, &key, &data, flags)) {
--- 1732,1744 ----
  
      CHECK_DB_NOT_CLOSED(self);
!     if (!make_key_dbt(self, keyobj, &key, NULL))
!         return NULL;
!     if ( !make_dbt(dataobj, &data) ||
!          !add_partial_dbt(&data, dlen, doff) ||
!          !checkTxnObj(txnobj, &txn) )
!     {
!         FREE_DBT(key);
!         return NULL;
!     }
  
      if (-1 == _DB_put(self, txn, &key, &data, flags)) {
***************
*** 2391,2396 ****
      if (!make_key_dbt(self, keyobj, &key, NULL))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn))
          return NULL;
  
      /* This causes ENOMEM to be returned when the db has the key because
--- 2408,2415 ----
      if (!make_key_dbt(self, keyobj, &key, NULL))
          return NULL;
!     if (!checkTxnObj(txnobj, &txn)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      /* This causes ENOMEM to be returned when the db has the key because
***************
*** 2693,2704 ****
      if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
          return NULL;
!     if (dataobj && !make_dbt(dataobj, &data))
!         return NULL;
!     if (!add_partial_dbt(&data, dlen, doff))
          return NULL;
  
      if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
          data.flags = DB_DBT_MALLOC;
!         key.flags = DB_DBT_MALLOC;
      }
  
--- 2712,2727 ----
      if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL))
          return NULL;
!     if ( (dataobj && !make_dbt(dataobj, &data)) ||
!          (!add_partial_dbt(&data, dlen, doff)) )
!     {
!         FREE_DBT(key);
          return NULL;
+     }
  
      if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
          data.flags = DB_DBT_MALLOC;
!         if (!(key.flags & DB_DBT_REALLOC)) {
!             key.flags |= DB_DBT_MALLOC;
!         }
      }
  
***************
*** 2707,2711 ****
      MYDB_END_ALLOW_THREADS;
  
- 
      if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) {
          Py_INCREF(Py_None);
--- 2730,2733 ----
***************
*** 2732,2738 ****
              break;
          }
-         FREE_DBT(key);
          FREE_DBT(data);
      }
      return retval;
  }
--- 2754,2760 ----
              break;
          }
          FREE_DBT(data);
      }
+     FREE_DBT(key);
      return retval;
  }
***************
*** 2811,2817 ****
      if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
          return NULL;
!     if (!make_dbt(dataobj, &data))
          return NULL;
!     if (!add_partial_dbt(&data, dlen, doff)) return NULL;
  
      MYDB_BEGIN_ALLOW_THREADS;
--- 2833,2842 ----
      if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
          return NULL;
!     if (!make_dbt(dataobj, &data) ||
!         !add_partial_dbt(&data, dlen, doff) )
!     {
!         FREE_DBT(key);
          return NULL;
!     }
  
      MYDB_BEGIN_ALLOW_THREADS;
***************
*** 2849,2854 ****
          data.flags = DB_DBT_MALLOC;
      }
!     if (!add_partial_dbt(&data, dlen, doff))
          return NULL;
  
      MYDB_BEGIN_ALLOW_THREADS;
--- 2874,2881 ----
          data.flags = DB_DBT_MALLOC;
      }
!     if (!add_partial_dbt(&data, dlen, doff)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      MYDB_BEGIN_ALLOW_THREADS;
***************
*** 2879,2885 ****
              break;
          }
-         FREE_DBT(key);
          FREE_DBT(data);
      }
  
      return retval;
--- 2906,2912 ----
              break;
          }
          FREE_DBT(data);
      }
+     FREE_DBT(key);
  
      return retval;
***************
*** 2907,2917 ****
  
      CLEAR_DBT(data);
      if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
          /* Tell BerkeleyDB to malloc the return value (thread safe) */
!         data.flags = DB_DBT_MALLOC;
!         key.flags = DB_DBT_MALLOC;
      }
-     if (!add_partial_dbt(&data, dlen, doff))
-         return NULL;
      MYDB_BEGIN_ALLOW_THREADS;
      err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
--- 2934,2949 ----
  
      CLEAR_DBT(data);
+     if (!add_partial_dbt(&data, dlen, doff)) {
+         FREE_DBT(key);
+         return NULL;
+     }
      if (CHECK_DBFLAG(self->mydb, DB_THREAD)) {
          /* Tell BerkeleyDB to malloc the return value (thread safe) */
!         data.flags |= DB_DBT_MALLOC;
!         /* only BTREE databases will return anything in the key */
!         if (!(key.flags & DB_DBT_REALLOC) && _DB_get_type(self->mydb) == DB_BTREE) {
!             key.flags |= DB_DBT_MALLOC;
!         }
      }
      MYDB_BEGIN_ALLOW_THREADS;
      err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE);
***************
*** 2941,2955 ****
              break;
          }
!         if (_DB_get_type(self->mydb) == DB_BTREE) {
!             /* the only time a malloced key is returned is when we
!              * call this on a BTree database because it performs
!              * partial matching and needs to return the real key.
!              * All others leave key untouched [where calling free()
!              * on it would often segfault].
!              */
!             FREE_DBT(key);
!         }
          FREE_DBT(data);
      }
  
      return retval;
--- 2973,2984 ----
              break;
          }
!         FREE_DBT(key);
          FREE_DBT(data);
      }
+     /* the only time REALLOC should be set is if we used an integer
+      * key that make_dbt_key malloc'd for us.  always free these. */
+     if (key.flags & DB_DBT_REALLOC) {
+         FREE_DBT(key);
+     }
  
      return retval;
***************
*** 2967,2972 ****
      if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
          return NULL;
!     if (!make_dbt(dataobj, &data))
          return NULL;
  
      MYDB_BEGIN_ALLOW_THREADS;
--- 2996,3003 ----
      if (!make_key_dbt(self->mydb, keyobj, &key, NULL))
          return NULL;
!     if (!make_dbt(dataobj, &data)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      MYDB_BEGIN_ALLOW_THREADS;
***************
*** 3105,3110 ****
          data.flags = DB_DBT_MALLOC;
      }
!     if (!add_partial_dbt(&data, dlen, doff))
          return NULL;
  
      MYDB_BEGIN_ALLOW_THREADS;
--- 3136,3143 ----
          data.flags = DB_DBT_MALLOC;
      }
!     if (!add_partial_dbt(&data, dlen, doff)) {
!         FREE_DBT(key);
          return NULL;
+     }
  
      MYDB_BEGIN_ALLOW_THREADS;
***************
*** 3121,3127 ****
          retval = Py_BuildValue("s#s#", key.data, key.size,
                                 data.data, data.size);
-         FREE_DBT(key);
          FREE_DBT(data);
      }
  
      return retval;
--- 3154,3160 ----
          retval = Py_BuildValue("s#s#", key.data, key.size,
                                 data.data, data.size);
          FREE_DBT(data);
      }
+     FREE_DBT(key);
  
      return retval;




More information about the Python-checkins mailing list