Skip to content

Commit 31d0cf9

Browse files
[3.14] gh-156100: Fix crashes in the sqlite3 Connection.autocommit setter (GH-156104) (GH-156152)
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) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent a434d87 commit 31d0cf9

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,
@@ -2673,6 +2678,11 @@ static int
26732678
set_autocommit(PyObject *op, PyObject *val, void *Py_UNUSED(closure))
26742679
{
26752680
pysqlite_Connection *self = _pysqlite_Connection_CAST(op);
2681+
if (val == NULL) {
2682+
PyErr_SetString(PyExc_AttributeError,
2683+
"cannot delete autocommit attribute");
2684+
return -1;
2685+
}
26762686
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
26772687
return -1;
26782688
}

0 commit comments

Comments
 (0)