Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix bugs in the constructor of :mod:`sqlite3.Connection` and
:meth:`sqlite3.Connection.close` where exceptions could be leaked. Patch by
Erlend E. Aasland.
68 changes: 51 additions & 17 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ static void _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);
static void connection_close(pysqlite_Connection *self);
static int connection_close(pysqlite_Connection *self);
PyObject *_pysqlite_query_execute(pysqlite_Cursor *, int, PyObject *, PyObject *);

static PyObject *
Expand Down Expand Up @@ -249,7 +249,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
if (self->initialized) {
PyTypeObject *tp = Py_TYPE(self);
tp->tp_clear((PyObject *)self);
connection_close(self);
if (connection_close(self) < 0) {
return -1;
Comment thread
erlend-aasland marked this conversation as resolved.
}
self->initialized = 0;
}

Expand Down Expand Up @@ -334,7 +336,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
self->initialized = 1;

if (autocommit == AUTOCOMMIT_DISABLED) {
(void)connection_exec_stmt(self, "BEGIN");
if (connection_exec_stmt(self, "BEGIN") < 0) {
return -1;
}
}
return 0;

Expand Down Expand Up @@ -432,48 +436,75 @@ free_callback_contexts(pysqlite_Connection *self)
static void
remove_callbacks(sqlite3 *db)
{
if (db == NULL) {
Comment thread
erlend-aasland marked this conversation as resolved.
Outdated
return;
}
sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0);
sqlite3_progress_handler(db, 0, 0, (void *)0);
(void)sqlite3_set_authorizer(db, NULL, NULL);
Comment thread
erlend-aasland marked this conversation as resolved.
Outdated
}

static void
static int
connection_close(pysqlite_Connection *self)
{
if (self->db) {
Comment thread
erlend-aasland marked this conversation as resolved.
Outdated
if (self->autocommit == AUTOCOMMIT_DISABLED &&
!sqlite3_get_autocommit(self->db))
{
/* If close is implicitly called as a result of interpreter
* tear-down, we must not call back into Python. */
if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) {
remove_callbacks(self->db);
if (connection_exec_stmt(self, "ROLLBACK") < 0) {
return -1;
Comment thread
erlend-aasland marked this conversation as resolved.
Outdated
}
(void)connection_exec_stmt(self, "ROLLBACK");
}

free_callback_contexts(self);

sqlite3 *db = self->db;
self->db = NULL;

Py_BEGIN_ALLOW_THREADS
int rc = sqlite3_close_v2(db);
assert(rc == SQLITE_OK), (void)rc;
Py_END_ALLOW_THREADS

free_callback_contexts(self);
}
return 0;
}

static void
connection_dealloc(pysqlite_Connection *self)
connection_finalize(PyObject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
tp->tp_clear((PyObject *)self);
pysqlite_Connection *con = (pysqlite_Connection *)self;
PyObject *exc = PyErr_GetRaisedException();

/* If close is implicitly called as a result of interpreter
* tear-down, we must not call back into Python. */
PyInterpreterState *interp = PyInterpreterState_Get();
int teardown = _Py_IsInterpreterFinalizing(interp);
if (teardown) {
Comment thread
erlend-aasland marked this conversation as resolved.
Outdated
remove_callbacks(con->db);
Comment thread
erlend-aasland marked this conversation as resolved.
}

/* Clean up if user has not called .close() explicitly. */
connection_close(self);
if (connection_close(con) < 0) {
if (teardown) {
PyErr_Clear();
}
else {
PyErr_WriteUnraisable((PyObject *)self);
}
}

PyErr_SetRaisedException(exc);
}

static void
connection_dealloc(PyObject *self)
{
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
return;
}
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
tp->tp_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -621,7 +652,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)

pysqlite_close_all_blobs(self);
Py_CLEAR(self->statement_cache);
connection_close(self);
if (connection_close(self) < 0) {
return NULL;
}

Py_RETURN_NONE;
}
Expand Down Expand Up @@ -2555,6 +2588,7 @@ static struct PyMemberDef connection_members[] =
};

static PyType_Slot connection_slots[] = {
{Py_tp_finalize, connection_finalize},
{Py_tp_dealloc, connection_dealloc},
{Py_tp_doc, (void *)connection_doc},
{Py_tp_methods, connection_methods},
Expand Down