Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4a84f58

Browse files
committed
Issue #10811: Fix recursive usage of cursors. Instead of crashing, raise a ProgrammingError now.
1 parent 1f30575 commit 4a84f58

4 files changed

Lines changed: 45 additions & 10 deletions

File tree

Lib/sqlite3/test/regression.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,28 @@ def collation_cb(a, b):
281281
# Lone surrogate cannot be encoded to the default encoding (utf8)
282282
"\uDC80", collation_cb)
283283

284+
def CheckRecursiveCursorUse(self):
285+
"""
286+
http://bugs.python.org/issue10811
287+
288+
Recursively using a cursor, such as when reusing it from a generator led to segfaults.
289+
Now we catch recursive cursor usage and raise a ProgrammingError.
290+
"""
291+
con = sqlite.connect(":memory:")
292+
293+
cur = con.cursor()
294+
cur.execute("create table a (bar)")
295+
cur.execute("create table b (baz)")
296+
297+
def foo():
298+
cur.execute("insert into a (bar) values (?)", (1,))
299+
yield 1
300+
301+
with self.assertRaises(sqlite.ProgrammingError):
302+
cur.executemany("insert into b (baz) values (?)",
303+
((i,) for i in foo()))
304+
305+
284306
def suite():
285307
regression_suite = unittest.makeSuite(RegressionTests, "Check")
286308
return unittest.TestSuite((regression_suite,))

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ Core and Builtins
113113
Library
114114
-------
115115

116+
- Issue #10811: Fix recursive usage of cursors. Instead of crashing,
117+
raise a ProgrammingError now.
118+
116119
- Issue #10881: Fix test_site failure with OS X framework builds.
117120

118121
- Issue #964437 Make IDLE help window non-modal.

Modules/_sqlite/cursor.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -433,9 +433,14 @@ static int check_cursor(pysqlite_Cursor* cur)
433433
if (cur->closed) {
434434
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
435435
return 0;
436-
} else {
437-
return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
438436
}
437+
438+
if (cur->locked) {
439+
PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed.");
440+
return 0;
441+
}
442+
443+
return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
439444
}
440445

441446
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
@@ -458,9 +463,10 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
458463
int allow_8bit_chars;
459464

460465
if (!check_cursor(self)) {
461-
return NULL;
466+
goto error;
462467
}
463468

469+
self->locked = 1;
464470
self->reset = 0;
465471

466472
/* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */
@@ -473,12 +479,12 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
473479
if (multiple) {
474480
/* executemany() */
475481
if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
476-
return NULL;
482+
goto error;
477483
}
478484

479485
if (!PyUnicode_Check(operation)) {
480486
PyErr_SetString(PyExc_ValueError, "operation parameter must be str");
481-
return NULL;
487+
goto error;
482488
}
483489

484490
if (PyIter_Check(second_argument)) {
@@ -489,23 +495,23 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
489495
/* sequence */
490496
parameters_iter = PyObject_GetIter(second_argument);
491497
if (!parameters_iter) {
492-
return NULL;
498+
goto error;
493499
}
494500
}
495501
} else {
496502
/* execute() */
497503
if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
498-
return NULL;
504+
goto error;
499505
}
500506

501507
if (!PyUnicode_Check(operation)) {
502508
PyErr_SetString(PyExc_ValueError, "operation parameter must be str");
503-
return NULL;
509+
goto error;
504510
}
505511

506512
parameters_list = PyList_New(0);
507513
if (!parameters_list) {
508-
return NULL;
514+
goto error;
509515
}
510516

511517
if (second_argument == NULL) {
@@ -745,14 +751,17 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
745751
* ROLLBACK could have happened */
746752
#ifdef SQLITE_VERSION_NUMBER
747753
#if SQLITE_VERSION_NUMBER >= 3002002
748-
self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
754+
if (self->connection && self->connection->db)
755+
self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
749756
#endif
750757
#endif
751758

752759
Py_XDECREF(parameters);
753760
Py_XDECREF(parameters_iter);
754761
Py_XDECREF(parameters_list);
755762

763+
self->locked = 0;
764+
756765
if (PyErr_Occurred()) {
757766
self->rowcount = -1L;
758767
return NULL;

Modules/_sqlite/cursor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef struct
4242
pysqlite_Statement* statement;
4343
int closed;
4444
int reset;
45+
int locked;
4546
int initialized;
4647

4748
/* the next row to be returned, NULL if no next row available */

0 commit comments

Comments
 (0)