Skip to content

Commit daebcac

Browse files
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.
1 parent 8e01c90 commit daebcac

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
@@ -104,11 +104,16 @@ autocommit_converter(PyObject *val, enum autocommit_mode *result)
104104
*result = AUTOCOMMIT_DISABLED;
105105
return 1;
106106
}
107-
if (PyLong_Check(val) &&
108-
PyLong_AsLong(val) == LEGACY_TRANSACTION_CONTROL)
109-
{
110-
*result = AUTOCOMMIT_LEGACY;
111-
return 1;
107+
if (PyLong_Check(val)) {
108+
int overflow;
109+
long value = PyLong_AsLongAndOverflow(val, &overflow);
110+
if (value == -1 && PyErr_Occurred()) {
111+
return 0;
112+
}
113+
if (!overflow && value == LEGACY_TRANSACTION_CONTROL) {
114+
*result = AUTOCOMMIT_LEGACY;
115+
return 1;
116+
}
112117
}
113118

114119
PyErr_SetString(PyExc_ValueError,
@@ -2621,6 +2626,11 @@ static int
26212626
set_autocommit(PyObject *op, PyObject *val, void *Py_UNUSED(closure))
26222627
{
26232628
pysqlite_Connection *self = _pysqlite_Connection_CAST(op);
2629+
if (val == NULL) {
2630+
PyErr_SetString(PyExc_AttributeError,
2631+
"cannot delete autocommit attribute");
2632+
return -1;
2633+
}
26242634
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
26252635
return -1;
26262636
}

0 commit comments

Comments
 (0)