summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2020-09-17 07:35:44 (GMT)
committerGitHub <noreply@github.com>2020-09-17 07:35:44 (GMT)
commit0b419b791077414bbc011a412698ebb362b63761 (patch)
treeee14bf8c868781a6d75c080acbaf110c94ae6270
parentdcfaa520c4638a67052a4ff4a2a820be68750ad7 (diff)
downloadcpython-0b419b791077414bbc011a412698ebb362b63761.zip
cpython-0b419b791077414bbc011a412698ebb362b63761.tar.gz
cpython-0b419b791077414bbc011a412698ebb362b63761.tar.bz2
bpo-41662: Fix bugs in binding parameters in sqlite3 (GH-21998)
* When the parameters argument is a list, correctly handle the case of changing it during iteration. * When the parameters argument is a custom sequence, no longer override an exception raised in ``__len__()``.
-rw-r--r--Lib/sqlite3/test/dbapi.py14
-rw-r--r--Lib/sqlite3/test/regression.py13
-rw-r--r--Misc/NEWS.d/next/Library/2020-08-29-16-07-36.bpo-41662.Mn79zh.rst1
-rw-r--r--Misc/NEWS.d/next/Library/2020-08-30-21-38-57.bpo-41662.6e9iZn.rst2
-rw-r--r--Modules/_sqlite/statement.c7
5 files changed, 34 insertions, 3 deletions
diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py
index a8dfeb9..7867bf3 100644
--- a/Lib/sqlite3/test/dbapi.py
+++ b/Lib/sqlite3/test/dbapi.py
@@ -270,7 +270,7 @@ class CursorTests(unittest.TestCase):
self.assertEqual(row[0], "foo")
def CheckExecuteParamSequence(self):
- class L(object):
+ class L:
def __len__(self):
return 1
def __getitem__(self, x):
@@ -282,6 +282,18 @@ class CursorTests(unittest.TestCase):
row = self.cu.fetchone()
self.assertEqual(row[0], "foo")
+ def CheckExecuteParamSequenceBadLen(self):
+ # Issue41662: Error in __len__() was overridden with ProgrammingError.
+ class L:
+ def __len__(self):
+ 1/0
+ def __getitem__(slf, x):
+ raise AssertionError
+
+ self.cu.execute("insert into test(name) values ('foo')")
+ with self.assertRaises(ZeroDivisionError):
+ self.cu.execute("select name from test where name=?", L())
+
def CheckExecuteDictMapping(self):
self.cu.execute("insert into test(name) values ('foo')")
self.cu.execute("select name from test where name=:name", {"name": "foo"})
diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py
index 0735a5c..67557e1 100644
--- a/Lib/sqlite3/test/regression.py
+++ b/Lib/sqlite3/test/regression.py
@@ -132,6 +132,19 @@ class RegressionTests(unittest.TestCase):
con.execute("insert into foo(bar) values (5)")
con.execute(SELECT)
+ def CheckBindMutatingList(self):
+ # Issue41662: Crash when mutate a list of parameters during iteration.
+ class X:
+ def __conform__(self, protocol):
+ parameters.clear()
+ return "..."
+ parameters = [X(), 0]
+ con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
+ con.execute("create table foo(bar X, baz integer)")
+ # Should not crash
+ with self.assertRaises(IndexError):
+ con.execute("insert into foo(bar, baz) values (?, ?)", parameters)
+
def CheckErrorMsgDecodeError(self):
# When porting the module to Python 3.0, the error message about
# decoding errors disappeared. This verifies they're back again.
diff --git a/Misc/NEWS.d/next/Library/2020-08-29-16-07-36.bpo-41662.Mn79zh.rst b/Misc/NEWS.d/next/Library/2020-08-29-16-07-36.bpo-41662.Mn79zh.rst
new file mode 100644
index 0000000..0571c2d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-08-29-16-07-36.bpo-41662.Mn79zh.rst
@@ -0,0 +1 @@
+Fixed crash when mutate list of parameters during iteration in :mod:`sqlite3`.
diff --git a/Misc/NEWS.d/next/Library/2020-08-30-21-38-57.bpo-41662.6e9iZn.rst b/Misc/NEWS.d/next/Library/2020-08-30-21-38-57.bpo-41662.6e9iZn.rst
new file mode 100644
index 0000000..aecb0a1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-08-30-21-38-57.bpo-41662.6e9iZn.rst
@@ -0,0 +1,2 @@
+No longer override exceptions raised in ``__len__()`` of a sequence of
+parameters in :mod:`sqlite3` with :exc:`~sqlite3.ProgrammingError`.
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index 26599b4..02e47a0 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -227,6 +227,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
num_params = PyList_GET_SIZE(parameters);
} else {
num_params = PySequence_Size(parameters);
+ if (num_params == -1) {
+ return;
+ }
}
if (num_params != num_params_needed) {
PyErr_Format(pysqlite_ProgrammingError,
@@ -238,9 +241,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
for (i = 0; i < num_params; i++) {
if (PyTuple_CheckExact(parameters)) {
current_param = PyTuple_GET_ITEM(parameters, i);
- Py_XINCREF(current_param);
+ Py_INCREF(current_param);
} else if (PyList_CheckExact(parameters)) {
- current_param = PyList_GET_ITEM(parameters, i);
+ current_param = PyList_GetItem(parameters, i);
Py_XINCREF(current_param);
} else {
current_param = PySequence_GetItem(parameters, i);