| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3ff5ef2 commit fd19509
2 files changed
| Original file line number | Diff line number | Diff 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. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -149,7 +149,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); | |||
| 149 | 149 | static void free_callback_context(callback_context *ctx); | |
| 150 | 150 | static void set_callback_context(callback_context **ctx_pp, | |
| 151 | 151 | callback_context *ctx); | |
| 152 | - static void connection_close(pysqlite_Connection *self); | ||
| 152 | + static int connection_close(pysqlite_Connection *self); | ||
| 153 | 153 | PyObject *_pysqlite_query_execute(pysqlite_Cursor *, int, PyObject *, PyObject *); | |
| 154 | 154 | ||
| 155 | 155 | static PyObject * | |
@@ -247,10 +247,13 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, | |||
| 247 | 247 | } | |
| 248 | 248 | ||
| 249 | 249 | if (self->initialized) { | |
| 250 | + self->initialized = 0; | ||
| 251 | + | ||
| 250 | 252 | PyTypeObject *tp = Py_TYPE(self); | |
| 251 | 253 | tp->tp_clear((PyObject *)self); | |
| 252 | - connection_close(self); | ||
| 253 | - self->initialized = 0; | ||
| 254 | + if (connection_close(self) < 0) { | ||
| 255 | + return -1; | ||
| 256 | + } | ||
| 254 | 257 | } | |
| 255 | 258 | ||
| 256 | 259 | // Create and configure SQLite database object. | |
@@ -334,7 +337,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, | |||
| 334 | 337 | self->initialized = 1; | |
| 335 | 338 | ||
| 336 | 339 | if (autocommit == AUTOCOMMIT_DISABLED) { | |
| 337 | - (void)connection_exec_stmt(self, "BEGIN"); | ||
| 340 | + if (connection_exec_stmt(self, "BEGIN") < 0) { | ||
| 341 | + return -1; | ||
| 342 | + } | ||
| 338 | 343 | } | |
| 339 | 344 | return 0; | |
| 340 | 345 | ||
@@ -432,48 +437,83 @@ free_callback_contexts(pysqlite_Connection *self) | |||
| 432 | 437 | static void | |
| 433 | 438 | remove_callbacks(sqlite3 *db) | |
| 434 | 439 | { | |
| 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 | + | ||
| 436 | 446 | 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; | ||
| 438 | 450 | } | |
| 439 | 451 | ||
| 440 | - static void | ||
| 452 | + static int | ||
| 441 | 453 | connection_close(pysqlite_Connection *self) | |
| 442 | 454 | { | |
| 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; | ||
| 453 | 465 | } | |
| 466 | + } | ||
| 454 | 467 | ||
| 455 | - free_callback_contexts(self); | ||
| 468 | + sqlite3 *db = self->db; | ||
| 469 | + self->db = NULL; | ||
| 456 | 470 | ||
| 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 | ||
| 459 | 476 | ||
| 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; | ||
| 465 | 479 | } | |
| 466 | 480 | ||
| 467 | 481 | static void | |
| 468 | - connection_dealloc(pysqlite_Connection *self) | ||
| 482 | + connection_finalize(PyObject *self) | ||
| 469 | 483 | { | |
| 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 | + } | ||
| 473 | 494 | ||
| 474 | 495 | /* 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 | + } | ||
| 476 | 507 | ||
| 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); | ||
| 477 | 517 | tp->tp_free(self); | |
| 478 | 518 | Py_DECREF(tp); | |
| 479 | 519 | } | |
@@ -621,7 +661,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self) | |||
| 621 | 661 | ||
| 622 | 662 | pysqlite_close_all_blobs(self); | |
| 623 | 663 | Py_CLEAR(self->statement_cache); | |
| 624 | - connection_close(self); | ||
| 664 | + if (connection_close(self) < 0) { | ||
| 665 | + return NULL; | ||
| 666 | + } | ||
| 625 | 667 | ||
| 626 | 668 | Py_RETURN_NONE; | |
| 627 | 669 | } | |
@@ -2555,6 +2597,7 @@ static struct PyMemberDef connection_members[] = | |||
| 2555 | 2597 | }; | |
| 2556 | 2598 | ||
| 2557 | 2599 | static PyType_Slot connection_slots[] = { | |
| 2600 | + {Py_tp_finalize, connection_finalize}, | ||
| 2558 | 2601 | {Py_tp_dealloc, connection_dealloc}, | |
| 2559 | 2602 | {Py_tp_doc, (void *)connection_doc}, | |
| 2560 | 2603 | {Py_tp_methods, connection_methods}, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments