Skip to content

Commit d0a3eff

Browse files
authored
gh-139327: fix some reference leaks in sqlite3 error branches (#139328)
1 parent d936dbe commit d0a3eff

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);
@@ -561,7 +561,10 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory)
561561
return NULL;
562562
}
563563

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

566569
if (cursor && self->row_factory != Py_None) {
567570
Py_INCREF(self->row_factory);
@@ -1060,32 +1063,36 @@ final_callback(sqlite3_context *context)
10601063
PyGILState_Release(threadstate);
10611064
}
10621065

1063-
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
1066+
static int
1067+
_pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
10641068
{
10651069
/* we only need to do this once in a while */
10661070
if (self->created_cursors++ < 200) {
1067-
return;
1071+
return 0;
10681072
}
10691073

10701074
self->created_cursors = 0;
10711075

10721076
PyObject* new_list = PyList_New(0);
10731077
if (!new_list) {
1074-
return;
1078+
return -1;
10751079
}
10761080

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

10881094
Py_SETREF(self->cursors, new_list);
1095+
return 0;
10891096
}
10901097

10911098
/* 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)