diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py index 417a53109c87c7..3ddd2f8ec5da5a 100644 --- a/Lib/sqlite3/test/regression.py +++ b/Lib/sqlite3/test/regression.py @@ -414,6 +414,33 @@ def test_return_empty_bytestring(self): val = cur.fetchone()[0] self.assertEqual(val, b'') + def test_uninitialized_isolation_level(self): + """ + Previously trying to get the isolation level of an uninitialized Connection + caused a segfault, now it should just return None. + """ + conn = sqlite.Connection.__new__(sqlite.Connection) + with self.assertRaises(sqlite.ProgrammingError): + conn.isolation_level + + def test_cursor_invalid_isolation_level(self): + """ + When trying to call conn.cursor() when conn is a Connection object that + was not initialized properly, it caused a segfault. Now it should raise + a ProgrammingError. + """ + conn = sqlite.Connection.__new__(sqlite.Connection) + self.assertRaises(ValueError, conn.__init__, '', isolation_level='invalid isolation level') + self.assertRaises(sqlite.ProgrammingError, conn.cursor) + + + def test_close_invalid_connection(self): + """ + Trying to call close() on a connection which was not initialized properly, + it caused a segfault. Now it should raise a ProgrammingError. + """ + conn = sqlite.Connection.__new__(sqlite.Connection) + self.assertRaises(sqlite.ProgrammingError, conn.close) def suite(): tests = [ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 5f8e41b6169a76..b52d1819a903c2 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -118,11 +118,15 @@ pysqlite_connection_init(pysqlite_Connection *self, PyObject *args, if (!isolation_level) { isolation_level = PyUnicode_FromString(""); if (!isolation_level) { + PyErr_SetString(pysqlite_ProgrammingError, "Isolation level could not be set."); return -1; } } else { Py_INCREF(isolation_level); } + + self->initialized = 1; + Py_CLEAR(self->isolation_level); if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) < 0) { Py_DECREF(isolation_level); @@ -250,8 +254,19 @@ pysqlite_connection_dealloc(pysqlite_Connection *self) */ int pysqlite_connection_register_cursor(pysqlite_Connection* connection, PyObject* cursor) { + if (!connection || !connection->cursors) { + PyErr_Format(pysqlite_ProgrammingError, + "Base Connection.__init__ not called."); + goto error; + } PyObject* weakref; + if (!connection->cursors) { + PyErr_SetString(pysqlite_ProgrammingError, + "Base Connection.__init__ not called."); + goto error; + } + weakref = PyWeakref_NewRef((PyObject*)cursor, NULL); if (!weakref) { goto error; @@ -281,6 +296,11 @@ static PyObject * pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory) /*[clinic end generated code: output=562432a9e6af2aa1 input=4127345aa091b650]*/ { + if (self == NULL) { + return NULL; + } + + static char *kwlist[] = {"factory", NULL}; PyObject* cursor; if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { @@ -323,6 +343,12 @@ pysqlite_connection_close_impl(pysqlite_Connection *self) /*[clinic end generated code: output=a546a0da212c9b97 input=3d58064bbffaa3d3]*/ { int rc; + + if (!self->statements) { + PyErr_SetString(pysqlite_ProgrammingError, + "Base Connection.__init__ not called."); + return NULL; + } if (!pysqlite_check_thread(self)) { return NULL; @@ -1225,6 +1251,11 @@ int pysqlite_check_thread(pysqlite_Connection* self) static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* self, void* unused) { + if (!self || !self->isolation_level) { + PyErr_Format(pysqlite_ProgrammingError, + "Object is null or isolation_level is uninitialized."); + return 0; + } return Py_NewRef(self->isolation_level); }