diff --git a/Lib/test/test_sqlite3/test_transactions.py b/Lib/test/test_sqlite3/test_transactions.py index a3de7a7a82ec1cb..2e5d60fe9ba5fc0 100644 --- a/Lib/test/test_sqlite3/test_transactions.py +++ b/Lib/test/test_sqlite3/test_transactions.py @@ -389,10 +389,25 @@ def test_autocommit_setget(self): def test_autocommit_setget_invalid(self): msg = "autocommit must be True, False, or.*LEGACY" - for mode in "a", 12, (), None: + for mode in "a", 12, (), None, 2**1000, -2**1000: with self.subTest(mode=mode): with self.assertRaisesRegex(ValueError, msg): sqlite.connect(":memory:", autocommit=mode) + with memory_database() as cx: + with self.assertRaisesRegex(ValueError, msg): + cx.autocommit = mode + # a failed assignment does not change the value + self.assertEqual(cx.autocommit, + sqlite.LEGACY_TRANSACTION_CONTROL) + + def test_autocommit_delete(self): + with memory_database() as cx: + cx.autocommit = False + with self.assertRaisesRegex(AttributeError, + "cannot delete autocommit attribute"): + del cx.autocommit + # a failed deletion does not change the value + self.assertIs(cx.autocommit, False) def test_autocommit_disabled(self): expected = [ diff --git a/Misc/NEWS.d/next/Library/2026-08-20-12-05-00.gh-issue-156100.Lm7qWz.rst b/Misc/NEWS.d/next/Library/2026-08-20-12-05-00.gh-issue-156100.Lm7qWz.rst new file mode 100644 index 000000000000000..8c296a9a8919fc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-20-12-05-00.gh-issue-156100.Lm7qWz.rst @@ -0,0 +1,4 @@ +Fix crashes in :class:`sqlite3.Connection` when deleting the +:attr:`~sqlite3.Connection.autocommit` attribute or setting it to an integer +which does not fit in C :c:expr:`long`. +Both now raise an exception. diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 892740b05e55c98..ec47471873f7822 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -104,11 +104,16 @@ autocommit_converter(PyObject *val, enum autocommit_mode *result) *result = AUTOCOMMIT_DISABLED; return 1; } - if (PyLong_Check(val) && - PyLong_AsLong(val) == LEGACY_TRANSACTION_CONTROL) - { - *result = AUTOCOMMIT_LEGACY; - return 1; + if (PyLong_Check(val)) { + int overflow; + long value = PyLong_AsLongAndOverflow(val, &overflow); + if (value == -1 && PyErr_Occurred()) { + return 0; + } + if (!overflow && value == LEGACY_TRANSACTION_CONTROL) { + *result = AUTOCOMMIT_LEGACY; + return 1; + } } PyErr_SetString(PyExc_ValueError, @@ -2621,6 +2626,11 @@ static int set_autocommit(PyObject *op, PyObject *val, void *Py_UNUSED(closure)) { pysqlite_Connection *self = _pysqlite_Connection_CAST(op); + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "cannot delete autocommit attribute"); + return -1; + } if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return -1; }