|
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)) |
@@ -376,12 +391,9 @@ static int check_cursor(pysqlite_Cursor* cur) |
376 | 391 | return 0; |
377 | 392 | } |
378 | 393 |
|
379 | | - if (cur->locked) { |
380 | | - PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed."); |
381 | | - return 0; |
382 | | - } |
383 | | - |
384 | | - return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); |
| 394 | + return (pysqlite_check_thread(cur->connection) |
| 395 | + && pysqlite_check_connection(cur->connection) |
| 396 | + && check_cursor_locked(cur)); |
385 | 397 | } |
386 | 398 |
|
387 | 399 | PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) |
@@ -790,27 +802,29 @@ PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self) |
790 | 802 | if (self->statement) { |
791 | 803 | rc = pysqlite_step(self->statement->st, self->connection); |
792 | 804 | if (PyErr_Occurred()) { |
793 | | - (void)pysqlite_statement_reset(self->statement); |
794 | | - Py_DECREF(next_row); |
795 | | - return NULL; |
| 805 | + goto error; |
796 | 806 | } |
797 | 807 | if (rc != SQLITE_DONE && rc != SQLITE_ROW) { |
798 | | - (void)pysqlite_statement_reset(self->statement); |
799 | | - Py_DECREF(next_row); |
800 | 808 | _pysqlite_seterror(self->connection->db, NULL); |
801 | | - return NULL; |
| 809 | + goto error; |
802 | 810 | } |
803 | 811 |
|
804 | 812 | if (rc == SQLITE_ROW) { |
| 813 | + self->locked = 1; // GH-80254: Prevent recursive use of cursors. |
805 | 814 | self->next_row = _pysqlite_fetch_one_row(self); |
| 815 | + self->locked = 0; |
806 | 816 | if (self->next_row == NULL) { |
807 | | - (void)pysqlite_statement_reset(self->statement); |
808 | | - return NULL; |
| 817 | + goto error; |
809 | 818 | } |
810 | 819 | } |
811 | 820 | } |
812 | 821 |
|
813 | 822 | return next_row; |
| 823 | + |
| 824 | +error: |
| 825 | + (void)pysqlite_statement_reset(self->statement); |
| 826 | + Py_DECREF(next_row); |
| 827 | + return NULL; |
814 | 828 | } |
815 | 829 |
|
816 | 830 | PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args) |
@@ -905,6 +919,10 @@ PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args) |
905 | 919 |
|
906 | 920 | PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args) |
907 | 921 | { |
| 922 | + if (!check_cursor_locked(self)) { |
| 923 | + return NULL; |
| 924 | + } |
| 925 | + |
908 | 926 | if (!self->connection) { |
909 | 927 | PyErr_SetString(pysqlite_ProgrammingError, |
910 | 928 | "Base Cursor.__init__ not called."); |
|
0 commit comments