|
27 | 27 |
|
28 | 28 | PyObject* pysqlite_cursor_iternext(pysqlite_Cursor* self);
|
29 | 29 |
|
| 30 | +static inline int |
| 31 | +check_cursor_locked(pysqlite_Cursor *cur) |
| 32 | +{ |
| 33 | + if (cur->locked) { |
| 34 | + PyErr_SetString(pysqlite_ProgrammingError, |
| 35 | + "Recursive use of cursors not allowed."); |
| 36 | + return 0; |
| 37 | + } |
| 38 | + return 1; |
| 39 | +} |
| 40 | + |
30 | 41 | static const char errmsg_fetch_across_rollback[] = "Cursor needed to be reset because of commit/rollback and can no longer be fetched from.";
|
31 | 42 |
|
32 | 43 | static int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
|
33 | 44 | {
|
| 45 | + if (!check_cursor_locked(self)) { |
| 46 | + return -1; |
| 47 | + } |
| 48 | + |
34 | 49 | pysqlite_Connection* connection;
|
35 | 50 |
|
36 | 51 | if (!PyArg_ParseTuple(args, "O!", &pysqlite_ConnectionType, &connection))
|
@@ -357,12 +372,9 @@ static int check_cursor(pysqlite_Cursor* cur)
|
357 | 372 | return 0;
|
358 | 373 | }
|
359 | 374 |
|
360 |
| - if (cur->locked) { |
361 |
| - PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed."); |
362 |
| - return 0; |
363 |
| - } |
364 |
| - |
365 |
| - return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); |
| 375 | + return (pysqlite_check_thread(cur->connection) |
| 376 | + && pysqlite_check_connection(cur->connection) |
| 377 | + && check_cursor_locked(cur)); |
366 | 378 | }
|
367 | 379 |
|
368 | 380 | static PyObject *
|
@@ -750,27 +762,29 @@ PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
|
750 | 762 | if (self->statement) {
|
751 | 763 | rc = pysqlite_step(self->statement->st, self->connection);
|
752 | 764 | if (PyErr_Occurred()) {
|
753 |
| - (void)pysqlite_statement_reset(self->statement); |
754 |
| - Py_DECREF(next_row); |
755 |
| - return NULL; |
| 765 | + goto error; |
756 | 766 | }
|
757 | 767 | if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
|
758 |
| - (void)pysqlite_statement_reset(self->statement); |
759 |
| - Py_DECREF(next_row); |
760 | 768 | _pysqlite_seterror(self->connection->db, NULL);
|
761 |
| - return NULL; |
| 769 | + goto error; |
762 | 770 | }
|
763 | 771 |
|
764 | 772 | if (rc == SQLITE_ROW) {
|
| 773 | + self->locked = 1; // GH-80254: Prevent recursive use of cursors. |
765 | 774 | self->next_row = _pysqlite_fetch_one_row(self);
|
| 775 | + self->locked = 0; |
766 | 776 | if (self->next_row == NULL) {
|
767 |
| - (void)pysqlite_statement_reset(self->statement); |
768 |
| - return NULL; |
| 777 | + goto error; |
769 | 778 | }
|
770 | 779 | }
|
771 | 780 | }
|
772 | 781 |
|
773 | 782 | return next_row;
|
| 783 | + |
| 784 | +error: |
| 785 | + (void)pysqlite_statement_reset(self->statement); |
| 786 | + Py_DECREF(next_row); |
| 787 | + return NULL; |
774 | 788 | }
|
775 | 789 |
|
776 | 790 | PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args)
|
@@ -857,6 +871,10 @@ PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args)
|
857 | 871 |
|
858 | 872 | PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args)
|
859 | 873 | {
|
| 874 | + if (!check_cursor_locked(self)) { |
| 875 | + return NULL; |
| 876 | + } |
| 877 | + |
860 | 878 | if (!self->connection) {
|
861 | 879 | PyErr_SetString(pysqlite_ProgrammingError,
|
862 | 880 | "Base Cursor.__init__ not called.");
|
|
0 commit comments