gh-139327: fix some reference leaks in sqlite3 error branches (#139328)

This commit is contained in:
Bénédikt Tran
2025-10-01 11:10:12 +02:00
committed by GitHub
parent d936dbeb1f
commit d0a3eff9d6
2 changed files with 42 additions and 32 deletions

View File

@@ -144,7 +144,7 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
static int _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
static void free_callback_context(callback_context *ctx);
static void set_callback_context(callback_context **ctx_pp,
callback_context *ctx);
@@ -561,7 +561,10 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory)
return NULL;
}
_pysqlite_drop_unused_cursor_references(self);
if (_pysqlite_drop_unused_cursor_references(self) < 0) {
Py_DECREF(cursor);
return NULL;
}
if (cursor && self->row_factory != Py_None) {
Py_INCREF(self->row_factory);
@@ -1060,32 +1063,36 @@ error:
PyGILState_Release(threadstate);
}
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
static int
_pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
{
/* we only need to do this once in a while */
if (self->created_cursors++ < 200) {
return;
return 0;
}
self->created_cursors = 0;
PyObject* new_list = PyList_New(0);
if (!new_list) {
return;
return -1;
}
for (Py_ssize_t i = 0; i < PyList_Size(self->cursors); i++) {
PyObject* weakref = PyList_GetItem(self->cursors, i);
assert(PyList_CheckExact(self->cursors));
Py_ssize_t imax = PyList_GET_SIZE(self->cursors);
for (Py_ssize_t i = 0; i < imax; i++) {
PyObject* weakref = PyList_GET_ITEM(self->cursors, i);
if (_PyWeakref_IsDead(weakref)) {
continue;
}
if (PyList_Append(new_list, weakref) != 0) {
Py_DECREF(new_list);
return;
return -1;
}
}
Py_SETREF(self->cursors, new_list);
return 0;
}
/* Allocate a UDF/callback context structure. In order to ensure that the state

View File

@@ -471,6 +471,9 @@ static int check_cursor(pysqlite_Cursor* cur)
return 0;
}
assert(cur->connection != NULL);
assert(cur->connection->state != NULL);
if (cur->closed) {
PyErr_SetString(cur->connection->state->ProgrammingError,
"Cannot operate on a closed cursor.");
@@ -567,43 +570,40 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
switch (paramtype) {
case TYPE_LONG: {
sqlite_int64 value = _pysqlite_long_as_int64(parameter);
if (value == -1 && PyErr_Occurred())
rc = -1;
else
rc = sqlite3_bind_int64(self->st, pos, value);
rc = (value == -1 && PyErr_Occurred())
? SQLITE_ERROR
: sqlite3_bind_int64(self->st, pos, value);
break;
}
case TYPE_FLOAT: {
double value = PyFloat_AsDouble(parameter);
if (value == -1 && PyErr_Occurred()) {
rc = -1;
}
else {
rc = sqlite3_bind_double(self->st, pos, value);
}
rc = (value == -1 && PyErr_Occurred())
? SQLITE_ERROR
: sqlite3_bind_double(self->st, pos, value);
break;
}
case TYPE_UNICODE:
string = PyUnicode_AsUTF8AndSize(parameter, &buflen);
if (string == NULL)
return -1;
if (string == NULL) {
return SQLITE_ERROR;
}
if (buflen > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"string longer than INT_MAX bytes");
return -1;
return SQLITE_ERROR;
}
rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT);
break;
case TYPE_BUFFER: {
Py_buffer view;
if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) {
return -1;
return SQLITE_ERROR;
}
if (view.len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"BLOB longer than INT_MAX bytes");
PyBuffer_Release(&view);
return -1;
return SQLITE_ERROR;
}
rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT);
PyBuffer_Release(&view);
@@ -613,7 +613,7 @@ bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
PyErr_Format(state->ProgrammingError,
"Error binding parameter %d: type '%s' is not supported",
pos, Py_TYPE(parameter)->tp_name);
rc = -1;
rc = SQLITE_ERROR;
}
final:
@@ -733,14 +733,17 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
}
binding_name++; /* skip first char (the colon) */
PyObject *current_param;
(void)PyMapping_GetOptionalItemString(parameters, binding_name, &current_param);
if (!current_param) {
if (!PyErr_Occurred() || PyErr_ExceptionMatches(PyExc_LookupError)) {
PyErr_Format(state->ProgrammingError,
"You did not supply a value for binding "
"parameter :%s.", binding_name);
}
PyObject *current_param = NULL;
int found = PyMapping_GetOptionalItemString(parameters,
binding_name,
&current_param);
if (found == -1) {
return;
}
else if (found == 0) {
PyErr_Format(state->ProgrammingError,
"You did not supply a value for binding "
"parameter :%s.", binding_name);
return;
}