pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/fd195092204aa7fc9f13c5c6d423bc723d0b3520

8caf1e80bb.css" /> gh-108083: Don't ignore exceptions in sqlite3.Connection.__init__() a… · python/cpython@fd19509 · GitHub
Skip to content

Commit fd19509

Browse files
erlend-aaslandvstinnerserhiy-storchaka
authored
gh-108083: Don't ignore exceptions in sqlite3.Connection.__init__() and .close() (#108084)
- Add explanatory comments - Add return value to connection_close() for propagating errors - Always check the return value of connection_exec_stmt() - Assert pre/post state in remove_callbacks() - Don't log unraisable exceptions in case of interpreter shutdown - Make sure we're not initialized if reinit fails - Try to close the database even if ROLLBACK fails Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 3ff5ef2 commit fd19509

File tree

2 files changed

+77
-31
lines changed

2 files changed

+77
-31
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix bugs in the constructor of :mod:`sqlite3.Connection` and
2+
:meth:`sqlite3.Connection.close` where exceptions could be leaked. Patch by
3+
Erlend E. Aasland.

Modules/_sqlite/connection.c

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
149149
static void free_callback_context(callback_context *ctx);
150150
static void set_callback_context(callback_context **ctx_pp,
151151
callback_context *ctx);
152-
static void connection_close(pysqlite_Connection *self);
152+
static int connection_close(pysqlite_Connection *self);
153153
PyObject *_pysqlite_query_execute(pysqlite_Cursor *, int, PyObject *, PyObject *);
154154

155155
static PyObject *
@@ -247,10 +247,13 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
247247
}
248248

249249
if (self->initialized) {
250+
self->initialized = 0;
251+
250252
PyTypeObject *tp = Py_TYPE(self);
251253
tp->tp_clear((PyObject *)self);
252-
connection_close(self);
253-
self->initialized = 0;
254+
if (connection_close(self) < 0) {
255+
return -1;
256+
}
254257
}
255258

256259
// Create and configure SQLite database object.
@@ -334,7 +337,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
334337
self->initialized = 1;
335338

336339
if (autocommit == AUTOCOMMIT_DISABLED) {
337-
(void)connection_exec_stmt(self, "BEGIN");
340+
if (connection_exec_stmt(self, "BEGIN") < 0) {
341+
return -1;
342+
}
338343
}
339344
return 0;
340345

@@ -432,48 +437,83 @@ free_callback_contexts(pysqlite_Connection *self)
432437
static void
433438
remove_callbacks(sqlite3 *db)
434439
{
435-
sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0);
440+
/* None of these APIs can fail, as long as they are given a valid
441+
* database pointer. */
442+
assert(db != NULL);
443+
int rc = sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0);
444+
assert(rc == SQLITE_OK), (void)rc;
445+
436446
sqlite3_progress_handler(db, 0, 0, (void *)0);
437-
(void)sqlite3_set_authorizer(db, NULL, NULL);
447+
448+
rc = sqlite3_set_authorizer(db, NULL, NULL);
449+
assert(rc == SQLITE_OK), (void)rc;
438450
}
439451

440-
static void
452+
static int
441453
connection_close(pysqlite_Connection *self)
442454
{
443-
if (self->db) {
444-
if (self->autocommit == AUTOCOMMIT_DISABLED &&
445-
!sqlite3_get_autocommit(self->db))
446-
{
447-
/* If close is implicitly called as a result of interpreter
448-
* tear-down, we must not call back into Python. */
449-
if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) {
450-
remove_callbacks(self->db);
451-
}
452-
(void)connection_exec_stmt(self, "ROLLBACK");
455+
if (self->db == NULL) {
456+
return 0;
457+
}
458+
459+
int rc = 0;
460+
if (self->autocommit == AUTOCOMMIT_DISABLED &&
461+
!sqlite3_get_autocommit(self->db))
462+
{
463+
if (connection_exec_stmt(self, "ROLLBACK") < 0) {
464+
rc = -1;
453465
}
466+
}
454467

455-
free_callback_contexts(self);
468+
sqlite3 *db = self->db;
469+
self->db = NULL;
456470

457-
sqlite3 *db = self->db;
458-
self->db = NULL;
471+
Py_BEGIN_ALLOW_THREADS
472+
/* The v2 close call always returns SQLITE_OK if given a valid database
473+
* pointer (which we do), so we can safely ignore the return value */
474+
(void)sqlite3_close_v2(db);
475+
Py_END_ALLOW_THREADS
459476

460-
Py_BEGIN_ALLOW_THREADS
461-
int rc = sqlite3_close_v2(db);
462-
assert(rc == SQLITE_OK), (void)rc;
463-
Py_END_ALLOW_THREADS
464-
}
477+
free_callback_contexts(self);
478+
return rc;
465479
}
466480

467481
static void
468-
connection_dealloc(pysqlite_Connection *self)
482+
connection_finalize(PyObject *self)
469483
{
470-
PyTypeObject *tp = Py_TYPE(self);
471-
PyObject_GC_UnTrack(self);
472-
tp->tp_clear((PyObject *)self);
484+
pysqlite_Connection *con = (pysqlite_Connection *)self;
485+
PyObject *exc = PyErr_GetRaisedException();
486+
487+
/* If close is implicitly called as a result of interpreter
488+
* tear-down, we must not call back into Python. */
489+
PyInterpreterState *interp = PyInterpreterState_Get();
490+
int teardown = _Py_IsInterpreterFinalizing(interp);
491+
if (teardown && con->db) {
492+
remove_callbacks(con->db);
493+
}
473494

474495
/* Clean up if user has not called .close() explicitly. */
475-
connection_close(self);
496+
if (connection_close(con) < 0) {
497+
if (teardown) {
498+
PyErr_Clear();
499+
}
500+
else {
501+
PyErr_WriteUnraisable((PyObject *)self);
502+
}
503+
}
504+
505+
PyErr_SetRaisedException(exc);
506+
}
476507

508+
static void
509+
connection_dealloc(PyObject *self)
510+
{
511+
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
512+
return;
513+
}
514+
PyTypeObject *tp = Py_TYPE(self);
515+
PyObject_GC_UnTrack(self);
516+
tp->tp_clear(self);
477517
tp->tp_free(self);
478518
Py_DECREF(tp);
479519
}
@@ -621,7 +661,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
621661

622662
pysqlite_close_all_blobs(self);
623663
Py_CLEAR(self->statement_cache);
624-
connection_close(self);
664+
if (connection_close(self) < 0) {
665+
return NULL;
666+
}
625667

626668
Py_RETURN_NONE;
627669
}
@@ -2555,6 +2597,7 @@ static struct PyMemberDef connection_members[] =
25552597
};
25562598

25572599
static PyType_Slot connection_slots[] = {
2600+
{Py_tp_finalize, connection_finalize},
25582601
{Py_tp_dealloc, connection_dealloc},
25592602
{Py_tp_doc, (void *)connection_doc},
25602603
{Py_tp_methods, connection_methods},

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy