|
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