|
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 *
|
@@ -761,27 +773,29 @@ PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
|
761 | 773 | if (self->statement) {
|
762 | 774 | rc = pysqlite_step(self->statement->st, self->connection);
|
763 | 775 | if (PyErr_Occurred()) {
|
764 |
| - (void)pysqlite_statement_reset(self->statement); |
765 |
| - Py_DECREF(next_row); |
766 |
| - return NULL; |
| 776 | + goto error; |
767 | 777 | }
|
768 | 778 | if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
|
769 |
| - (void)pysqlite_statement_reset(self->statement); |
770 |
| - Py_DECREF(next_row); |
771 | 779 | _pysqlite_seterror(self->connection->db, NULL);
|
772 |
| - return NULL; |
| 780 | + goto error; |
773 | 781 | }
|
774 | 782 |
|
775 | 783 | if (rc == SQLITE_ROW) {
|
| 784 | + self->locked = 1; // GH-80254: Prevent recursive use of cursors. |
776 | 785 | self->next_row = _pysqlite_fetch_one_row(self);
|
| 786 | + self->locked = 0; |
777 | 787 | if (self->next_row == NULL) {
|
778 |
| - (void)pysqlite_statement_reset(self->statement); |
779 |
| - return NULL; |
| 788 | + goto error; |
780 | 789 | }
|
781 | 790 | }
|
782 | 791 | }
|
783 | 792 |
|
784 | 793 | return next_row;
|
| 794 | + |
| 795 | +error: |
| 796 | + (void)pysqlite_statement_reset(self->statement); |
| 797 | + Py_DECREF(next_row); |
| 798 | + return NULL; |
785 | 799 | }
|
786 | 800 |
|
787 | 801 | PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args)
|
@@ -876,6 +890,10 @@ PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args)
|
876 | 890 |
|
877 | 891 | PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args)
|
878 | 892 | {
|
| 893 | + if (!check_cursor_locked(self)) { |
| 894 | + return NULL; |
| 895 | + } |
| 896 | + |
879 | 897 | if (!self->connection) {
|
880 | 898 | PyErr_SetString(pysqlite_ProgrammingError,
|
881 | 899 | "Base Cursor.__init__ not called.");
|
|
0 commit comments