Skip to content

Commit 0cb470e

Browse files
author
Erlend Egeberg Aasland
authored
[3.10] bpo-31746: Prevent segfaults when sqlite3.Connection is uninitialised (GH-27431). (GH-27472)
(cherry picked from commit 7e311e4) Co-authored-by: Erlend Egeberg Aasland <[email protected]>
1 parent 4729976 commit 0cb470e

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

Lib/sqlite3/test/dbapi.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,26 @@ def test_open_uri(self):
197197
cx.execute('insert into test(id) values(1)')
198198

199199

200+
class UninitialisedConnectionTests(unittest.TestCase):
201+
def setUp(self):
202+
self.cx = sqlite.Connection.__new__(sqlite.Connection)
203+
204+
def test_uninit_operations(self):
205+
funcs = (
206+
lambda: self.cx.isolation_level,
207+
lambda: self.cx.total_changes,
208+
lambda: self.cx.in_transaction,
209+
lambda: self.cx.iterdump(),
210+
lambda: self.cx.cursor(),
211+
lambda: self.cx.close(),
212+
)
213+
for func in funcs:
214+
with self.subTest(func=func):
215+
self.assertRaisesRegex(sqlite.ProgrammingError,
216+
"Base Connection.__init__ not called",
217+
func)
218+
219+
200220
class CursorTests(unittest.TestCase):
201221
def setUp(self):
202222
self.cx = sqlite.connect(":memory:")
@@ -949,6 +969,7 @@ def suite():
949969
ModuleTests,
950970
SqliteOnConflictTests,
951971
ThreadTests,
972+
UninitialisedConnectionTests,
952973
]
953974
return unittest.TestSuite(
954975
[unittest.TestLoader().loadTestsFromTestCase(t) for t in tests]

Modules/_sqlite/connection.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ pysqlite_connection_init(pysqlite_Connection *self, PyObject *args,
9292

9393
database = PyBytes_AsString(database_obj);
9494

95-
self->initialized = 1;
96-
9795
self->begin_statement = NULL;
9896

9997
Py_CLEAR(self->statement_cache);
@@ -128,7 +126,7 @@ pysqlite_connection_init(pysqlite_Connection *self, PyObject *args,
128126
Py_INCREF(isolation_level);
129127
}
130128
Py_CLEAR(self->isolation_level);
131-
if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) < 0) {
129+
if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) != 0) {
132130
Py_DECREF(isolation_level);
133131
return -1;
134132
}
@@ -187,6 +185,8 @@ pysqlite_connection_init(pysqlite_Connection *self, PyObject *args,
187185
return -1;
188186
}
189187

188+
self->initialized = 1;
189+
190190
return 0;
191191
}
192192

@@ -359,6 +359,12 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
359359
return NULL;
360360
}
361361

362+
if (!self->initialized) {
363+
PyErr_SetString(pysqlite_ProgrammingError,
364+
"Base Connection.__init__ not called.");
365+
return NULL;
366+
}
367+
362368
pysqlite_do_all_statements(self, ACTION_FINALIZE, 1);
363369

364370
if (self->db) {
@@ -1264,6 +1270,9 @@ int pysqlite_check_thread(pysqlite_Connection* self)
12641270

12651271
static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* self, void* unused)
12661272
{
1273+
if (!pysqlite_check_connection(self)) {
1274+
return NULL;
1275+
}
12671276
return Py_NewRef(self->isolation_level);
12681277
}
12691278

@@ -1295,11 +1304,17 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso
12951304
return -1;
12961305
}
12971306
if (isolation_level == Py_None) {
1298-
PyObject *res = pysqlite_connection_commit(self, NULL);
1299-
if (!res) {
1300-
return -1;
1307+
/* We might get called during connection init, so we cannot use
1308+
* pysqlite_connection_commit() here. */
1309+
if (self->db && !sqlite3_get_autocommit(self->db)) {
1310+
int rc;
1311+
Py_BEGIN_ALLOW_THREADS
1312+
rc = sqlite3_exec(self->db, "COMMIT", NULL, NULL, NULL);
1313+
Py_END_ALLOW_THREADS
1314+
if (rc != SQLITE_OK) {
1315+
return _pysqlite_seterror(self->db, NULL);
1316+
}
13011317
}
1302-
Py_DECREF(res);
13031318

13041319
self->begin_statement = NULL;
13051320
} else {

0 commit comments

Comments
 (0)