diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index 776659e3b16108..8dd3b951d53658 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -146,6 +146,14 @@ def test_sqlite_row_index(self): with self.assertRaises(IndexError): row[complex()] # index must be int or string + def test_delete_connection_row_factory(self): + # gh-149738: deleting row_factory should not segfault + del self.con.row_factory + with self.assertRaises(sqlite.OperationalError): + self.con.execute("test") + cur = self.con.cursor() + self.assertIsNone(cur.row_factory) + def test_sqlite_row_index_unicode(self): row = self.con.execute("select 1 as \xff").fetchone() self.assertEqual(row["\xff"], 1) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst new file mode 100644 index 00000000000000..fccd1f5c4ae678 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-13-06-54-41.gh-issue-149738.4BLFoH.rst @@ -0,0 +1,2 @@ +Fix a segmentation fault in :mod:`sqlite3` when ``row_factory`` is deleted +and a query is executed afterward. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index bd44ff31b87c67..ee9d8bf9ac4a68 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -549,7 +549,7 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory) return NULL; } - if (cursor && self->row_factory != Py_None) { + if (cursor && self->row_factory && self->row_factory != Py_None) { Py_INCREF(self->row_factory); Py_XSETREF(((pysqlite_Cursor *)cursor)->row_factory, self->row_factory); }