@@ -58,6 +58,41 @@ check_cursor_locked(pysqlite_Cursor *cur)
5858 return 1 ;
5959}
6060
61+ static pysqlite_state *
62+ get_module_state_by_cursor (pysqlite_Cursor * cursor )
63+ {
64+ if (cursor -> connection != NULL && cursor -> connection -> state != NULL ) {
65+ return cursor -> connection -> state ;
66+ }
67+ return pysqlite_get_state_by_type (Py_TYPE (cursor ));
68+ }
69+
70+ static void
71+ cursor_sqlite3_internal_error (pysqlite_Cursor * cursor ,
72+ const char * error_message ,
73+ int chain_exceptions )
74+ {
75+ pysqlite_state * state = get_module_state_by_cursor (cursor );
76+ if (chain_exceptions ) {
77+ assert (PyErr_Occurred ());
78+ PyObject * exc = PyErr_GetRaisedException ();
79+ PyErr_SetString (state -> InternalError , error_message );
80+ _PyErr_ChainExceptions1 (exc );
81+ }
82+ else {
83+ assert (!PyErr_Occurred ());
84+ PyErr_SetString (state -> InternalError , error_message );
85+ }
86+ }
87+
88+ static void
89+ cursor_cannot_reset_stmt_error (pysqlite_Cursor * cursor , int chain_exceptions )
90+ {
91+ cursor_sqlite3_internal_error (cursor ,
92+ "cannot reset statement" ,
93+ chain_exceptions );
94+ }
95+
6196/*[clinic input]
6297module _sqlite3
6398class _sqlite3.Cursor "pysqlite_Cursor *" "clinic_state()->CursorType"
@@ -173,8 +208,12 @@ cursor_clear(PyObject *op)
173208 Py_CLEAR (self -> row_factory );
174209 if (self -> statement ) {
175210 /* Reset the statement if the user has not closed the cursor */
176- stmt_reset (self -> statement );
211+ int rc = stmt_reset (self -> statement );
177212 Py_CLEAR (self -> statement );
213+ if (rc != SQLITE_OK ) {
214+ cursor_cannot_reset_stmt_error (self , 0 );
215+ PyErr_FormatUnraisable ("Exception ignored in cursor_clear()" );
216+ }
178217 }
179218
180219 return 0 ;
@@ -837,7 +876,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
837876
838877 if (self -> statement ) {
839878 // Reset pending statements on this cursor.
840- (void )stmt_reset (self -> statement );
879+ if (stmt_reset (self -> statement ) != SQLITE_OK ) {
880+ goto reset_failure ;
881+ }
841882 }
842883
843884 PyObject * stmt = get_statement_from_cache (self , operation );
@@ -861,7 +902,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
861902 }
862903 }
863904
864- (void )stmt_reset (self -> statement );
905+ if (stmt_reset (self -> statement ) != SQLITE_OK ) {
906+ goto reset_failure ;
907+ }
865908 self -> rowcount = self -> statement -> is_dml ? 0L : -1L ;
866909
867910 /* We start a transaction implicitly before a DML statement.
@@ -943,7 +986,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
943986 if (self -> statement -> is_dml ) {
944987 self -> rowcount += (long )sqlite3_changes (self -> connection -> db );
945988 }
946- stmt_reset (self -> statement );
989+ if (stmt_reset (self -> statement ) != SQLITE_OK ) {
990+ goto reset_failure ;
991+ }
947992 }
948993 Py_XDECREF (parameters );
949994 }
@@ -968,8 +1013,15 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
9681013
9691014 if (PyErr_Occurred ()) {
9701015 if (self -> statement ) {
971- (void )stmt_reset (self -> statement );
1016+ sqlite3 * db = sqlite3_db_handle (self -> statement -> st );
1017+ int sqlite3_state = sqlite3_errcode (db );
1018+ // stmt_reset() may return a previously set exception,
1019+ // either triggered because of Python or sqlite3.
1020+ rc = stmt_reset (self -> statement );
9721021 Py_CLEAR (self -> statement );
1022+ if (sqlite3_state == SQLITE_OK && rc != SQLITE_OK ) {
1023+ cursor_cannot_reset_stmt_error (self , 1 );
1024+ }
9731025 }
9741026 self -> rowcount = -1L ;
9751027 return NULL ;
@@ -978,6 +1030,20 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
9781030 Py_CLEAR (self -> statement );
9791031 }
9801032 return Py_NewRef ((PyObject * )self );
1033+
1034+ reset_failure :
1035+ /* suite to execute when stmt_reset() failed and no exception is set */
1036+ assert (!PyErr_Occurred ());
1037+
1038+ Py_XDECREF (parameters );
1039+ Py_XDECREF (parameters_iter );
1040+ Py_XDECREF (parameters_list );
1041+
1042+ self -> locked = 0 ;
1043+ self -> rowcount = -1L ;
1044+ Py_CLEAR (self -> statement );
1045+ cursor_cannot_reset_stmt_error (self , 0 );
1046+ return NULL ;
9811047}
9821048
9831049/*[clinic input]
@@ -1120,14 +1186,20 @@ pysqlite_cursor_iternext(PyObject *op)
11201186 if (self -> statement -> is_dml ) {
11211187 self -> rowcount = (long )sqlite3_changes (self -> connection -> db );
11221188 }
1123- ( void ) stmt_reset (self -> statement );
1189+ rc = stmt_reset (self -> statement );
11241190 Py_CLEAR (self -> statement );
1191+ if (rc != SQLITE_OK ) {
1192+ goto reset_failure ;
1193+ }
11251194 }
11261195 else if (rc != SQLITE_ROW ) {
1127- set_error_from_db (self -> connection -> state , self -> connection -> db );
1128- ( void ) stmt_reset (self -> statement );
1196+ rc = set_error_from_db (self -> connection -> state , self -> connection -> db );
1197+ int reset_rc = stmt_reset (self -> statement );
11291198 Py_CLEAR (self -> statement );
11301199 Py_DECREF (row );
1200+ if (rc == SQLITE_OK && reset_rc != SQLITE_OK ) {
1201+ goto reset_failure ;
1202+ }
11311203 return NULL ;
11321204 }
11331205 if (!Py_IsNone (self -> row_factory )) {
@@ -1137,6 +1209,10 @@ pysqlite_cursor_iternext(PyObject *op)
11371209 Py_SETREF (row , new_row );
11381210 }
11391211 return row ;
1212+
1213+ reset_failure :
1214+ cursor_cannot_reset_stmt_error (self , 0 );
1215+ return NULL ;
11401216}
11411217
11421218/*[clinic input]
@@ -1291,8 +1367,15 @@ pysqlite_cursor_close_impl(pysqlite_Cursor *self)
12911367 }
12921368
12931369 if (self -> statement ) {
1294- (void )stmt_reset (self -> statement );
1370+ int rc = stmt_reset (self -> statement );
1371+ // Force self->statement to be NULL even if stmt_reset() may have
1372+ // failed to avoid a possible double-free if someone calls close()
1373+ // twice as a leak here would be better than a double-free.
12951374 Py_CLEAR (self -> statement );
1375+ if (rc != SQLITE_OK ) {
1376+ cursor_cannot_reset_stmt_error (self , 0 );
1377+ return NULL ;
1378+ }
12961379 }
12971380
12981381 self -> closed = 1 ;
0 commit comments