Skip to content

Commit 6d94af4

Browse files
[3.14] gh-139327: fix some reference leaks in sqlite3 error branches (GH-139328) (GH-139471)
(cherry picked from commit d0a3eff) Co-authored-by: Bénédikt Tran <[email protected]>
1 parent b4c3c0f commit 6d94af4

File tree

2 files changed

+42
-32
lines changed

2 files changed

+42
-32
lines changed

Modules/_sqlite/connection.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp
144144
[clinic start generated code]*/
145145
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/
146146

147-
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
147+
static int _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
148148
static void free_callback_context(callback_context *ctx);
149149
static void set_callback_context(callback_context **ctx_pp,
150150
callback_context *ctx);
@@ -562,7 +562,10 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory)
562562
return NULL;
563563
}
564564

565-
_pysqlite_drop_unused_cursor_references(self);
565+
if (_pysqlite_drop_unused_cursor_references(self) < 0) {
566+
Py_DECREF(cursor);
567+
return NULL;
568+
}
566569

567570
if (cursor && self->row_factory != Py_None) {
568571
Py_INCREF(self->row_factory);
@@ -1061,32 +1064,36 @@ final_callback(sqlite3_context *context)
10611064
PyGILState_Release(threadstate);
10621065
}
10631066

1064-
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
1067+
static int
1068+
_pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
10651069
{
10661070
/* we only need to do this once in a while */
10671071
if (self->created_cursors++ < 200) {
1068-
return;
1072+
return 0;
10691073
}
10701074

10711075
self->created_cursors = 0;
10721076

10731077
PyObject* new_list = PyList_New(0);
10741078
if (!new_list) {
1075-
return;
1079+
return -1;
10761080
}
10771081

1078-
for (Py_ssize_t i = 0; i < PyList_Size(self->cursors); i++) {
1079-
PyObject* weakref = PyList_GetItem(self->cursors, i);
1082+
assert(PyList_CheckExact(self->cursors));
1083+
Py_ssize_t imax = PyList_GET_SIZE(self->cursors);
1084+
for (Py_ssize_t i = 0; i < imax; i++) {
1085+
PyObject* weakref = PyList_GET_ITEM(self->cursors, i);
10801086
if (_PyWeakref_IsDead(weakref)) {
10811087
continue;
10821088
}
10831089
if (PyList_Append(new_list, weakref) != 0) {
10841090
Py_DECREF(new_list);
1085-
return;
1091+
return -1;
10861092
}
10871093
}
10881094

10891095
Py_SETREF(self->cursors, new_list);
1096+
return 0;
10901097
}
10911098

10921099
/* Allocate a UDF/callback context structure. In order to ensure that the state

Modules/_sqlite/cursor.c

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ static int check_cursor(pysqlite_Cursor* cur)
471471
return 0;
472472
}
473473

474+
assert(cur->connection != NULL);
475+
assert(cur->connection->state != NULL);
476+
474477
if (cur->closed) {
475478
PyErr_SetString(cur->connection->state->ProgrammingError,
476479
"Cannot operate on a closed cursor.");
@@ -567,43 +570,40 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
567570
switch (paramtype) {
568571
case TYPE_LONG: {
569572
sqlite_int64 value = _pysqlite_long_as_int64(parameter);
570-
if (value == -1 && PyErr_Occurred())
571-
rc = -1;
572-
else
573-
rc = sqlite3_bind_int64(self->st, pos, value);
573+
rc = (value == -1 && PyErr_Occurred())
574+
? SQLITE_ERROR
575+
: sqlite3_bind_int64(self->st, pos, value);
574576
break;
575577
}
576578
case TYPE_FLOAT: {
577579
double value = PyFloat_AsDouble(parameter);
578-
if (value == -1 && PyErr_Occurred()) {
579-
rc = -1;
580-
}
581-
else {
582-
rc = sqlite3_bind_double(self->st, pos, value);
583-
}
580+
rc = (value == -1 && PyErr_Occurred())
581+
? SQLITE_ERROR
582+
: sqlite3_bind_double(self->st, pos, value);
584583
break;
585584
}
586585
case TYPE_UNICODE:
587586
string = PyUnicode_AsUTF8AndSize(parameter, &buflen);
588-
if (string == NULL)
589-
return -1;
587+
if (string == NULL) {
588+
return SQLITE_ERROR;
589+
}
590590
if (buflen > INT_MAX) {
591591
PyErr_SetString(PyExc_OverflowError,
592592
"string longer than INT_MAX bytes");
593-
return -1;
593+
return SQLITE_ERROR;
594594
}
595595
rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT);
596596
break;
597597
case TYPE_BUFFER: {
598598
Py_buffer view;
599599
if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) {
600-
return -1;
600+
return SQLITE_ERROR;
601601
}
602602
if (view.len > INT_MAX) {
603603
PyErr_SetString(PyExc_OverflowError,
604604
"BLOB longer than INT_MAX bytes");
605605
PyBuffer_Release(&view);
606-
return -1;
606+
return SQLITE_ERROR;
607607
}
608608
rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT);
609609
PyBuffer_Release(&view);
@@ -613,7 +613,7 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
613613
PyErr_Format(state->ProgrammingError,
614614
"Error binding parameter %d: type '%s' is not supported",
615615
pos, Py_TYPE(parameter)->tp_name);
616-
rc = -1;
616+
rc = SQLITE_ERROR;
617617
}
618618

619619
final:
@@ -733,14 +733,17 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
733733
}
734734

735735
binding_name++; /* skip first char (the colon) */
736-
PyObject *current_param;
737-
(void)PyMapping_GetOptionalItemString(parameters, binding_name, &current_param);
738-
if (!current_param) {
739-
if (!PyErr_Occurred() || PyErr_ExceptionMatches(PyExc_LookupError)) {
740-
PyErr_Format(state->ProgrammingError,
741-
"You did not supply a value for binding "
742-
"parameter :%s.", binding_name);
743-
}
736+
PyObject *current_param = NULL;
737+
int found = PyMapping_GetOptionalItemString(parameters,
738+
binding_name,
739+
&current_param);
740+
if (found == -1) {
741+
return;
742+
}
743+
else if (found == 0) {
744+
PyErr_Format(state->ProgrammingError,
745+
"You did not supply a value for binding "
746+
"parameter :%s.", binding_name);
744747
return;
745748
}
746749

0 commit comments

Comments
 (0)