? Lib/bsddb/test/valgrind.out ? Lib/bsddb/test/valgrind.out.2 ? Lib/bsddb/test/valgrind.out.all ? Lib/bsddb/test/valgrind.out.all.2 ? Lib/bsddb/test/valgrind.out.basics Index: Modules/_bsddb.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_bsddb.c,v retrieving revision 1.31 diff -u -r1.31 _bsddb.c --- Modules/_bsddb.c 25 Mar 2004 02:16:22 -0000 1.31 +++ Modules/_bsddb.c 27 Jun 2004 23:27:02 -0000 @@ -297,7 +297,7 @@ #define CLEAR_DBT(dbt) (memset(&(dbt), 0, sizeof(dbt))) #define FREE_DBT(dbt) if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \ - dbt.data != NULL) { free(dbt.data); } + dbt.data != NULL) { free(dbt.data); dbt.data = NULL; } static int makeDBError(int err); @@ -330,7 +330,7 @@ } 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."); + "Data values must be of type string or None."); return 0; } return 1; @@ -340,7 +340,7 @@ /* Recno and Queue DBs can have integer keys. This function figures out what's been given, verifies that it's allowed, and then makes the DBT. - Caller should call FREE_DBT(key) when done. */ + Caller MUST call FREE_DBT(key) when done. */ static int make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags) { @@ -1298,11 +1298,15 @@ CHECK_DB_NOT_CLOSED(self); if (!make_key_dbt(self, keyobj, &key, NULL)) return NULL; - if (!checkTxnObj(txnobj, &txn)) + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); return NULL; + } - if (-1 == _DB_delete(self, txn, &key, 0)) + if (-1 == _DB_delete(self, txn, &key, 0)) { + FREE_DBT(key); return NULL; + } FREE_DBT(key); RETURN_NONE(); @@ -1348,16 +1352,20 @@ CHECK_DB_NOT_CLOSED(self); if (!make_key_dbt(self, keyobj, &key, &flags)) return NULL; - if (!checkTxnObj(txnobj, &txn)) + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); return NULL; + } CLEAR_DBT(data); if (CHECK_DBFLAG(self, DB_THREAD)) { /* Tell BerkeleyDB to malloc the return value (thread safe) */ data.flags = DB_DBT_MALLOC; } - if (!add_partial_dbt(&data, dlen, doff)) + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); return NULL; + } MYDB_BEGIN_ALLOW_THREADS; err = self->db->get(self->db, txn, &key, &data, flags); @@ -1379,9 +1387,9 @@ data.size); else /* return just the data */ retval = PyString_FromStringAndSize((char*)data.data, data.size); - FREE_DBT(key); FREE_DBT(data); } + FREE_DBT(key); RETURN_IF_ERR(); return retval; @@ -1406,8 +1414,10 @@ CHECK_DB_NOT_CLOSED(self); if (!make_key_dbt(self, keyobj, &key, &flags)) return NULL; - if (!checkTxnObj(txnobj, &txn)) + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); return NULL; + } CLEAR_DBT(data); /* We don't allocate any memory, forcing a ENOMEM error and thus @@ -1449,10 +1459,12 @@ CHECK_DB_NOT_CLOSED(self); if (!make_key_dbt(self, keyobj, &key, NULL)) return NULL; - if (!make_dbt(dataobj, &data)) - return NULL; - if (!checkTxnObj(txnobj, &txn)) + if ( !make_dbt(dataobj, &data) || + !checkTxnObj(txnobj, &txn) ) + { + FREE_DBT(key); return NULL; + } flags |= DB_GET_BOTH; @@ -1719,10 +1731,15 @@ return NULL; 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 (!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)) { FREE_DBT(key); @@ -2390,8 +2407,10 @@ CHECK_DB_NOT_CLOSED(self); if (!make_key_dbt(self, keyobj, &key, NULL)) return NULL; - if (!checkTxnObj(txnobj, &txn)) + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); return NULL; + } /* This causes ENOMEM to be returned when the db has the key because it has a record but can't allocate a buffer for the data. This saves @@ -2692,21 +2711,24 @@ 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)) + 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; - key.flags = DB_DBT_MALLOC; + if (!(key.flags & DB_DBT_REALLOC)) { + key.flags |= DB_DBT_MALLOC; + } } MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags); MYDB_END_ALLOW_THREADS; - if ((err == DB_NOTFOUND) && self->mydb->moduleFlags.getReturnsNone) { Py_INCREF(Py_None); retval = Py_None; @@ -2731,9 +2753,9 @@ data.data, data.size); break; } - FREE_DBT(key); FREE_DBT(data); } + FREE_DBT(key); return retval; } @@ -2810,9 +2832,12 @@ if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) return NULL; - if (!make_dbt(dataobj, &data)) + if (!make_dbt(dataobj, &data) || + !add_partial_dbt(&data, dlen, doff) ) + { + FREE_DBT(key); return NULL; - if (!add_partial_dbt(&data, dlen, doff)) return NULL; + } MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_put(self->dbc, &key, &data, flags); @@ -2848,8 +2873,10 @@ /* Tell BerkeleyDB to malloc the return value (thread safe) */ data.flags = DB_DBT_MALLOC; } - if (!add_partial_dbt(&data, dlen, doff)) + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); return NULL; + } MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET); @@ -2878,9 +2905,9 @@ data.data, data.size); break; } - FREE_DBT(key); FREE_DBT(data); } + FREE_DBT(key); return retval; } @@ -2906,13 +2933,18 @@ return NULL; 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; - key.flags = DB_DBT_MALLOC; + 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; + } } - 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); MYDB_END_ALLOW_THREADS; @@ -2940,17 +2972,14 @@ data.data, data.size); 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(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; } @@ -2966,8 +2995,10 @@ /* the caller did this: CHECK_CURSOR_NOT_CLOSED(self); */ if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) return NULL; - if (!make_dbt(dataobj, &data)) + if (!make_dbt(dataobj, &data)) { + FREE_DBT(key); return NULL; + } MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH); @@ -3104,8 +3135,10 @@ /* Tell BerkeleyDB to malloc the return value (thread safe) */ data.flags = DB_DBT_MALLOC; } - if (!add_partial_dbt(&data, dlen, doff)) + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); return NULL; + } MYDB_BEGIN_ALLOW_THREADS; err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO); @@ -3120,9 +3153,9 @@ else { /* Can only be used for BTrees, so no need to return int key */ retval = Py_BuildValue("s#s#", key.data, key.size, data.data, data.size); - FREE_DBT(key); FREE_DBT(data); } + FREE_DBT(key); return retval; } Index: Lib/bsddb/test/test_recno.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/bsddb/test/test_recno.py,v retrieving revision 1.7 diff -u -r1.7 test_recno.py --- Lib/bsddb/test/test_recno.py 21 Sep 2003 00:08:14 -0000 1.7 +++ Lib/bsddb/test/test_recno.py 27 Jun 2004 23:27:02 -0000 @@ -133,6 +133,13 @@ if verbose: print rec + # test that non-existant key lookups work (and that + # DBC_set_range doesn't have a memleak under valgrind) + rec = c.set_range(999999) + assert rec == None + if verbose: + print rec + c.close() d.close() @@ -177,6 +184,8 @@ """ source = os.path.join(os.path.dirname(sys.argv[0]), 'db_home/test_recno.txt') + if not os.path.isdir('db_home'): + os.mkdir('db_home') f = open(source, 'w') # create the file f.close()