Skip to content

Commit be8f3a6

Browse files
[3.13] gh-139327: fix some reference leaks in sqlite3 error branches (GH-139328) (#139472)
(cherry picked from commit d0a3eff) Co-authored-by: Bénédikt Tran <[email protected]>
1 parent 35da905 commit be8f3a6

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
@@ -142,7 +142,7 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp
142142
[clinic start generated code]*/
143143
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/
144144

145-
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
145+
static int _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
146146
static void free_callback_context(callback_context *ctx);
147147
static void set_callback_context(callback_context **ctx_pp,
148148
callback_context *ctx);
@@ -556,7 +556,10 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory)
556556
return NULL;
557557
}
558558

559-
_pysqlite_drop_unused_cursor_references(self);
559+
if (_pysqlite_drop_unused_cursor_references(self) < 0) {
560+
Py_DECREF(cursor);
561+
return NULL;
562+
}
560563

561564
if (cursor && self->row_factory != Py_None) {
562565
Py_INCREF(self->row_factory);
@@ -1054,32 +1057,36 @@ final_callback(sqlite3_context *context)
10541057
PyGILState_Release(threadstate);
10551058
}
10561059

1057-
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
1060+
static int
1061+
_pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
10581062
{
10591063
/* we only need to do this once in a while */
10601064
if (self->created_cursors++ < 200) {
1061-
return;
1065+
return 0;
10621066
}
10631067

10641068
self->created_cursors = 0;
10651069

10661070
PyObject* new_list = PyList_New(0);
10671071
if (!new_list) {
1068-
return;
1072+
return -1;
10691073
}
10701074

1071-
for (Py_ssize_t i = 0; i < PyList_Size(self->cursors); i++) {
1072-
PyObject* weakref = PyList_GetItem(self->cursors, i);
1075+
assert(PyList_CheckExact(self->cursors));
1076+
Py_ssize_t imax = PyList_GET_SIZE(self->cursors);
1077+
for (Py_ssize_t i = 0; i < imax; i++) {
1078+
PyObject* weakref = PyList_GET_ITEM(self->cursors, i);
10731079
if (_PyWeakref_IsDead(weakref)) {
10741080
continue;
10751081
}
10761082
if (PyList_Append(new_list, weakref) != 0) {
10771083
Py_DECREF(new_list);
1078-
return;
1084+
return -1;
10791085
}
10801086
}
10811087

10821088
Py_SETREF(self->cursors, new_list);
1089+
return 0;
10831090
}
10841091

10851092
/* 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
@@ -466,6 +466,9 @@ static int check_cursor(pysqlite_Cursor* cur)
466466
return 0;
467467
}
468468

469+
assert(cur->connection != NULL);
470+
assert(cur->connection->state != NULL);
471+
469472
if (cur->closed) {
470473
PyErr_SetString(cur->connection->state->ProgrammingError,
471474
"Cannot operate on a closed cursor.");
@@ -562,43 +565,40 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
562565
switch (paramtype) {
563566
case TYPE_LONG: {
564567
sqlite_int64 value = _pysqlite_long_as_int64(parameter);
565-
if (value == -1 && PyErr_Occurred())
566-
rc = -1;
567-
else
568-
rc = sqlite3_bind_int64(self->st, pos, value);
568+
rc = (value == -1 && PyErr_Occurred())
569+
? SQLITE_ERROR
570+
: sqlite3_bind_int64(self->st, pos, value);
569571
break;
570572
}
571573
case TYPE_FLOAT: {
572574
double value = PyFloat_AsDouble(parameter);
573-
if (value == -1 && PyErr_Occurred()) {
574-
rc = -1;
575-
}
576-
else {
577-
rc = sqlite3_bind_double(self->st, pos, value);
578-
}
575+
rc = (value == -1 && PyErr_Occurred())
576+
? SQLITE_ERROR
577+
: sqlite3_bind_double(self->st, pos, value);
579578
break;
580579
}
581580
case TYPE_UNICODE:
582581
string = PyUnicode_AsUTF8AndSize(parameter, &buflen);
583-
if (string == NULL)
584-
return -1;
582+
if (string == NULL) {
583+
return SQLITE_ERROR;
584+
}
585585
if (buflen > INT_MAX) {
586586
PyErr_SetString(PyExc_OverflowError,
587587
"string longer than INT_MAX bytes");
588-
return -1;
588+
return SQLITE_ERROR;
589589
}
590590
rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT);
591591
break;
592592
case TYPE_BUFFER: {
593593
Py_buffer view;
594594
if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) {
595-
return -1;
595+
return SQLITE_ERROR;
596596
}
597597
if (view.len > INT_MAX) {
598598
PyErr_SetString(PyExc_OverflowError,
599599
"BLOB longer than INT_MAX bytes");
600600
PyBuffer_Release(&view);
601-
return -1;
601+
return SQLITE_ERROR;
602602
}
603603
rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT);
604604
PyBuffer_Release(&view);
@@ -608,7 +608,7 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
608608
PyErr_Format(state->ProgrammingError,
609609
"Error binding parameter %d: type '%s' is not supported",
610610
pos, Py_TYPE(parameter)->tp_name);
611-
rc = -1;
611+
rc = SQLITE_ERROR;
612612
}
613613

614614
final:
@@ -731,14 +731,17 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
731731
}
732732

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

0 commit comments

Comments
 (0)