Issue #10811: Fix recursive usage of cursors. Instead of crashing, raise a ProgrammingError now.

This commit is contained in:
Petri Lehtinen 2011-05-09 12:24:09 +02:00
parent cec6a61d30
commit c7fd523ac5
4 changed files with 45 additions and 10 deletions

View File

@ -264,6 +264,28 @@ class RegressionTests(unittest.TestCase):
""" """
self.assertRaises(sqlite.Warning, self.con, 1) 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(): def suite():
regression_suite = unittest.makeSuite(RegressionTests, "Check") regression_suite = unittest.makeSuite(RegressionTests, "Check")
return unittest.TestSuite((regression_suite,)) return unittest.TestSuite((regression_suite,))

View File

@ -90,6 +90,9 @@ Core and Builtins
Library 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 #10881: Fix test_site failures with OS X framework builds.
- Issue #964437 Make IDLE help window non-modal. - Issue #964437 Make IDLE help window non-modal.

View File

@ -443,9 +443,14 @@ static int check_cursor(pysqlite_Cursor* cur)
if (cur->closed) { if (cur->closed) {
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor."); PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
return 0; 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) 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; int allow_8bit_chars;
if (!check_cursor(self)) { if (!check_cursor(self)) {
return NULL; goto error;
} }
self->locked = 1;
self->reset = 0; self->reset = 0;
/* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */ /* 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) { if (multiple) {
/* executemany() */ /* executemany() */
if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) { if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
return NULL; goto error;
} }
if (!PyString_Check(operation) && !PyUnicode_Check(operation)) { if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode"); PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
return NULL; goto error;
} }
if (PyIter_Check(second_argument)) { if (PyIter_Check(second_argument)) {
@ -499,23 +505,23 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
/* sequence */ /* sequence */
parameters_iter = PyObject_GetIter(second_argument); parameters_iter = PyObject_GetIter(second_argument);
if (!parameters_iter) { if (!parameters_iter) {
return NULL; goto error;
} }
} }
} else { } else {
/* execute() */ /* execute() */
if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) { if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
return NULL; goto error;
} }
if (!PyString_Check(operation) && !PyUnicode_Check(operation)) { if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode"); PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
return NULL; goto error;
} }
parameters_list = PyList_New(0); parameters_list = PyList_New(0);
if (!parameters_list) { if (!parameters_list) {
return NULL; goto error;
} }
if (second_argument == NULL) { if (second_argument == NULL) {
@ -761,6 +767,7 @@ error:
* ROLLBACK could have happened */ * ROLLBACK could have happened */
#ifdef SQLITE_VERSION_NUMBER #ifdef SQLITE_VERSION_NUMBER
#if SQLITE_VERSION_NUMBER >= 3002002 #if SQLITE_VERSION_NUMBER >= 3002002
if (self->connection && self->connection->db)
self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db); self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
#endif #endif
#endif #endif
@ -770,6 +777,8 @@ error:
Py_XDECREF(parameters_iter); Py_XDECREF(parameters_iter);
Py_XDECREF(parameters_list); Py_XDECREF(parameters_list);
self->locked = 0;
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
self->rowcount = -1L; self->rowcount = -1L;
return NULL; return NULL;

View File

@ -42,6 +42,7 @@ typedef struct
pysqlite_Statement* statement; pysqlite_Statement* statement;
int closed; int closed;
int reset; int reset;
int locked;
int initialized; int initialized;
/* the next row to be returned, NULL if no next row available */ /* the next row to be returned, NULL if no next row available */