Skip to content

Commit fbf7a06

Browse files
[3.13] gh-156100: Fix crashes in the sqlite3 Connection.autocommit setter (GH-156104) (GH-156155)
Deleting the attribute crashed, and setting it to an integer which does not fit in C long reported success with OverflowError set. (cherry picked from commit daebcac)
1 parent 3800574 commit fbf7a06

3 files changed

Lines changed: 35 additions & 6 deletions

File tree

Lib/test/test_sqlite3/test_transactions.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,25 @@ def test_autocommit_setget(self):
389389

390390
def test_autocommit_setget_invalid(self):
391391
msg = "autocommit must be True, False, or.*LEGACY"
392-
for mode in "a", 12, (), None:
392+
for mode in "a", 12, (), None, 2**1000, -2**1000:
393393
with self.subTest(mode=mode):
394394
with self.assertRaisesRegex(ValueError, msg):
395395
sqlite.connect(":memory:", autocommit=mode)
396+
with memory_database() as cx:
397+
with self.assertRaisesRegex(ValueError, msg):
398+
cx.autocommit = mode
399+
# a failed assignment does not change the value
400+
self.assertEqual(cx.autocommit,
401+
sqlite.LEGACY_TRANSACTION_CONTROL)
402+
403+
def test_autocommit_delete(self):
404+
with memory_database() as cx:
405+
cx.autocommit = False
406+
with self.assertRaisesRegex(AttributeError,
407+
"cannot delete autocommit attribute"):
408+
del cx.autocommit
409+
# a failed deletion does not change the value
410+
self.assertIs(cx.autocommit, False)
396411

397412
def test_autocommit_disabled(self):
398413
expected = [
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix crashes in :class:`sqlite3.Connection` when deleting the
2+
:attr:`~sqlite3.Connection.autocommit` attribute or setting it to an integer
3+
which does not fit in C :c:expr:`long`.
4+
Both now raise an exception.

Modules/_sqlite/connection.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,16 @@ autocommit_converter(PyObject *val, enum autocommit_mode *result)
105105
*result = AUTOCOMMIT_DISABLED;
106106
return 1;
107107
}
108-
if (PyLong_Check(val) &&
109-
PyLong_AsLong(val) == LEGACY_TRANSACTION_CONTROL)
110-
{
111-
*result = AUTOCOMMIT_LEGACY;
112-
return 1;
108+
if (PyLong_Check(val)) {
109+
int overflow;
110+
long value = PyLong_AsLongAndOverflow(val, &overflow);
111+
if (value == -1 && PyErr_Occurred()) {
112+
return 0;
113+
}
114+
if (!overflow && value == LEGACY_TRANSACTION_CONTROL) {
115+
*result = AUTOCOMMIT_LEGACY;
116+
return 1;
117+
}
113118
}
114119

115120
PyErr_SetString(PyExc_ValueError,
@@ -2633,6 +2638,11 @@ get_autocommit(pysqlite_Connection *self, void *Py_UNUSED(ctx))
26332638
static int
26342639
set_autocommit(pysqlite_Connection *self, PyObject *val, void *Py_UNUSED(ctx))
26352640
{
2641+
if (val == NULL) {
2642+
PyErr_SetString(PyExc_AttributeError,
2643+
"cannot delete autocommit attribute");
2644+
return -1;
2645+
}
26362646
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
26372647
return -1;
26382648
}

0 commit comments

Comments
 (0)