gh-156100: Fix crashes in the sqlite3 Connection.autocommit setter (GH-156104)

serhiy-storchaka <[email protected]>
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/daebcac92d422d7fe9611cbe89044af23ea857c3
commit: daebcac92d422d7fe9611cbe89044af23ea857c3
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-21T10:04:25+03:00
summary:

gh-156100: Fix crashes in the sqlite3 Connection.autocommit setter (GH-156104)

Deleting the attribute crashed, and setting it to an integer which does not
fit in C long reported success with OverflowError set.

files:
A Misc/NEWS.d/next/Library/2026-08-20-12-05-00.gh-issue-156100.Lm7qWz.rst
M Lib/test/test_sqlite3/test_transactions.py
M Modules/_sqlite/connection.c

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;
     }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.