mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
[3.9] bpo-31746: Prevent segfaults when sqlite3.Connection is uninitialised (GH-27431) (GH-27465)
(cherry picked from commit 7e311e496b)
Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
This commit is contained in:
parent
c2c322b354
commit
0bc17658f5
2 changed files with 45 additions and 8 deletions
|
|
@ -192,6 +192,27 @@ def CheckSameThreadErrorOnOldVersion(self):
|
|||
sqlite.connect(':memory:', check_same_thread=False)
|
||||
self.assertEqual(str(cm.exception), 'shared connections not available')
|
||||
|
||||
|
||||
class UninitialisedConnectionTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cx = sqlite.Connection.__new__(sqlite.Connection)
|
||||
|
||||
def test_uninit_operations(self):
|
||||
funcs = (
|
||||
lambda: self.cx.isolation_level,
|
||||
lambda: self.cx.total_changes,
|
||||
lambda: self.cx.in_transaction,
|
||||
lambda: self.cx.iterdump(),
|
||||
lambda: self.cx.cursor(),
|
||||
lambda: self.cx.close(),
|
||||
)
|
||||
for func in funcs:
|
||||
with self.subTest(func=func):
|
||||
self.assertRaisesRegex(sqlite.ProgrammingError,
|
||||
"Base Connection.__init__ not called",
|
||||
func)
|
||||
|
||||
|
||||
class CursorTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cx = sqlite.connect(":memory:")
|
||||
|
|
@ -943,10 +964,11 @@ def suite():
|
|||
closed_con_suite = unittest.makeSuite(ClosedConTests, "Check")
|
||||
closed_cur_suite = unittest.makeSuite(ClosedCurTests, "Check")
|
||||
on_conflict_suite = unittest.makeSuite(SqliteOnConflictTests, "Check")
|
||||
uninit_con_suite = unittest.makeSuite(UninitialisedConnectionTests)
|
||||
return unittest.TestSuite((
|
||||
module_suite, connection_suite, cursor_suite, thread_suite,
|
||||
constructor_suite, ext_suite, closed_con_suite, closed_cur_suite,
|
||||
on_conflict_suite,
|
||||
on_conflict_suite, uninit_con_suite,
|
||||
))
|
||||
|
||||
def test():
|
||||
|
|
|
|||
|
|
@ -102,8 +102,6 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
|
|||
|
||||
database = PyBytes_AsString(database_obj);
|
||||
|
||||
self->initialized = 1;
|
||||
|
||||
self->begin_statement = NULL;
|
||||
|
||||
Py_CLEAR(self->statement_cache);
|
||||
|
|
@ -149,7 +147,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
|
|||
Py_INCREF(isolation_level);
|
||||
}
|
||||
Py_CLEAR(self->isolation_level);
|
||||
if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) < 0) {
|
||||
if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) != 0) {
|
||||
Py_DECREF(isolation_level);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -208,6 +206,8 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
|
|||
self->ProgrammingError = pysqlite_ProgrammingError;
|
||||
self->NotSupportedError = pysqlite_NotSupportedError;
|
||||
|
||||
self->initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -339,6 +339,12 @@ PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!self->initialized) {
|
||||
PyErr_SetString(pysqlite_ProgrammingError,
|
||||
"Base Connection.__init__ not called.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pysqlite_do_all_statements(self, ACTION_FINALIZE, 1);
|
||||
|
||||
if (self->db) {
|
||||
|
|
@ -1143,6 +1149,9 @@ int pysqlite_check_thread(pysqlite_Connection* self)
|
|||
|
||||
static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* self, void* unused)
|
||||
{
|
||||
if (!pysqlite_check_connection(self)) {
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(self->isolation_level);
|
||||
return self->isolation_level;
|
||||
}
|
||||
|
|
@ -1175,11 +1184,17 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso
|
|||
return -1;
|
||||
}
|
||||
if (isolation_level == Py_None) {
|
||||
PyObject *res = pysqlite_connection_commit(self, NULL);
|
||||
if (!res) {
|
||||
return -1;
|
||||
/* We might get called during connection init, so we cannot use
|
||||
* pysqlite_connection_commit() here. */
|
||||
if (self->db && !sqlite3_get_autocommit(self->db)) {
|
||||
int rc;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
rc = sqlite3_exec(self->db, "COMMIT", NULL, NULL, NULL);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (rc != SQLITE_OK) {
|
||||
return _pysqlite_seterror(self->db, NULL);
|
||||
}
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
self->begin_statement = NULL;
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue