]> granicus.if.org Git - python/commitdiff
Issue #10811: Fix recursive usage of cursors. Instead of crashing, raise a Programmin...
authorPetri Lehtinen <petri@digip.org>
Mon, 9 May 2011 10:24:09 +0000 (12:24 +0200)
committerPetri Lehtinen <petri@digip.org>
Mon, 6 Feb 2012 20:04:00 +0000 (22:04 +0200)
Lib/sqlite3/test/regression.py
Misc/NEWS
Modules/_sqlite/cursor.c
Modules/_sqlite/cursor.h

index 10300611999bfeccfe3ab366508926ae4d7209f8..eec2fcde95148a3727a918be98fed2cb90b9128e 100644 (file)
@@ -264,6 +264,28 @@ class RegressionTests(unittest.TestCase):
         """
         self.assertRaises(sqlite.Warning, self.con, 1)
 
+    def CheckRecursiveCursorUse(self):
+        """
+        http://bugs.python.org/issue10811
+
+        Recursively using a cursor, such as when reusing it from a generator led to segfaults.
+        Now we catch recursive cursor usage and raise a ProgrammingError.
+        """
+        con = sqlite.connect(":memory:")
+
+        cur = con.cursor()
+        cur.execute("create table a (bar)")
+        cur.execute("create table b (baz)")
+
+        def foo():
+            cur.execute("insert into a (bar) values (?)", (1,))
+            yield 1
+
+        with self.assertRaises(sqlite.ProgrammingError):
+            cur.executemany("insert into b (baz) values (?)",
+                            ((i,) for i in foo()))
+
+
 def suite():
     regression_suite = unittest.makeSuite(RegressionTests, "Check")
     return unittest.TestSuite((regression_suite,))
index c038d5f99a26f747cf74f775a052d33c5ac598a5..64c2a8acc267be72c44c7f2b1c896f157a2733dc 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -90,6 +90,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #10811: Fix recursive usage of cursors. Instead of crashing,
+  raise a ProgrammingError now.
+
 - Issue #10881: Fix test_site failures with OS X framework builds.
 
 - Issue #964437 Make IDLE help window non-modal.
index 028a80084f41123030aa5f05e81582653769b4da..e1cd536efc0d6e0c2c44b64cec40dda46bbb60b7 100644 (file)
@@ -443,9 +443,14 @@ static int check_cursor(pysqlite_Cursor* cur)
     if (cur->closed) {
         PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
         return 0;
-    } else {
-        return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
     }
+
+    if (cur->locked) {
+        PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed.");
+        return 0;
+    }
+
+    return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
 }
 
 PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
@@ -468,9 +473,10 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     int allow_8bit_chars;
 
     if (!check_cursor(self)) {
-        return NULL;
+        goto error;
     }
 
+    self->locked = 1;
     self->reset = 0;
 
     /* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */
@@ -483,12 +489,12 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     if (multiple) {
         /* executemany() */
         if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
-            return NULL;
+            goto error;
         }
 
         if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
             PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
-            return NULL;
+            goto error;
         }
 
         if (PyIter_Check(second_argument)) {
@@ -499,23 +505,23 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
             /* sequence */
             parameters_iter = PyObject_GetIter(second_argument);
             if (!parameters_iter) {
-                return NULL;
+                goto error;
             }
         }
     } else {
         /* execute() */
         if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
-            return NULL;
+            goto error;
         }
 
         if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
             PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
-            return NULL;
+            goto error;
         }
 
         parameters_list = PyList_New(0);
         if (!parameters_list) {
-            return NULL;
+            goto error;
         }
 
         if (second_argument == NULL) {
@@ -761,7 +767,8 @@ error:
      * ROLLBACK could have happened */
     #ifdef SQLITE_VERSION_NUMBER
     #if SQLITE_VERSION_NUMBER >= 3002002
-    self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
+    if (self->connection && self->connection->db)
+        self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
     #endif
     #endif
 
@@ -770,6 +777,8 @@ error:
     Py_XDECREF(parameters_iter);
     Py_XDECREF(parameters_list);
 
+    self->locked = 0;
+
     if (PyErr_Occurred()) {
         self->rowcount = -1L;
         return NULL;
index 82f5972a273ec37721be3e4211e8857300ddfc77..cf5389c898d30b39bd7e08a5eb1252c280ddb571 100644 (file)
@@ -42,6 +42,7 @@ typedef struct
     pysqlite_Statement* statement;
     int closed;
     int reset;
+    int locked;
     int initialized;
 
     /* the next row to be returned, NULL if no next row available */