]> granicus.if.org Git - python/commitdiff
Fix a double free when positioning a database cursor to a non-existant
authorGregory P. Smith <greg@mad-scientist.com>
Tue, 9 Oct 2007 06:50:43 +0000 (06:50 +0000)
committerGregory P. Smith <greg@mad-scientist.com>
Tue, 9 Oct 2007 06:50:43 +0000 (06:50 +0000)
string key (and probably a few other situations with string keys).
This was reported with a patch as pybsddb sourceforge bug 1708868 by
jjjhhhlll at gmail.

Lib/bsddb/test/test_misc.py
Modules/_bsddb.c

index 6b2df073c9f72a2846bbb990e3737292a11153bb..3e6335431667a71d24f598f4e4dc1e8bd8c4dbe7 100644 (file)
@@ -53,6 +53,26 @@ class MiscTestCase(unittest.TestCase):
         rp = repr(db)
         self.assertEquals(rp, "{}")
 
+    # http://sourceforge.net/tracker/index.php?func=detail&aid=1708868&group_id=13900&atid=313900
+    #
+    # See the bug report for details.
+    #
+    # The problem was that make_key_dbt() was not allocating a copy of
+    # string keys but FREE_DBT() was always being told to free it when the
+    # database was opened with DB_THREAD.
+    def test04_double_free_make_key_dbt(self):
+        try:
+            db1 = db.DB()
+            db1.open(self.filename, None, db.DB_BTREE,
+                     db.DB_CREATE | db.DB_THREAD)
+
+            curs = db1.cursor()
+            t = curs.get("/foo", db.DB_SET)
+            # double free happened during exit from DBC_get
+        finally:
+            db1.close()
+            os.unlink(self.filename)
+
 
 #----------------------------------------------------------------------
 
index c840eaf268e173fbf58f37adf9c2c12a62a5e0da..bc70cc3b0f5eb8de34d5b13ccbcd156b3e37ce28 100644 (file)
@@ -328,7 +328,19 @@ make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags)
             return 0;
         }
 
-        key->data = PyString_AS_STRING(keyobj);
+        /*
+         * NOTE(gps): I don't like doing a data copy here, it seems
+         * wasteful.  But without a clean way to tell FREE_DBT if it
+         * should free key->data or not we have to.  Other places in
+         * the code check for DB_THREAD and forceably set DBT_MALLOC
+         * when we otherwise would leave flags 0 to indicate that.
+         */
+        key->data = strdup(PyString_AS_STRING(keyobj));
+        if (key->data == NULL) {
+            PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed");
+            return 0;
+        }
+        key->flags = DB_DBT_REALLOC;
         key->size = PyString_GET_SIZE(keyobj);
     }