[Python-checkins] bpo-41662: Fix bugs in binding parameters in sqlite3 (GH-21998)

Serhiy Storchaka webhook-mailer at python.org
Thu Sep 17 03:35:49 EDT 2020


https://github.com/python/cpython/commit/0b419b791077414bbc011a412698ebb362b63761
commit: 0b419b791077414bbc011a412698ebb362b63761
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-09-17T10:35:44+03:00
summary:

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__()``.

files:
A Misc/NEWS.d/next/Library/2020-08-29-16-07-36.bpo-41662.Mn79zh.rst
A Misc/NEWS.d/next/Library/2020-08-30-21-38-57.bpo-41662.6e9iZn.rst
M Lib/sqlite3/test/dbapi.py
M Lib/sqlite3/test/regression.py
M Modules/_sqlite/statement.c

diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py
index a8dfeb9b2d693..7867bf361e5ac 100644
--- a/Lib/sqlite3/test/dbapi.py
+++ b/Lib/sqlite3/test/dbapi.py
@@ -270,7 +270,7 @@ def CheckExecuteParamList(self):
         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 @@ def __getitem__(self, x):
         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 0735a5c129226..67557e19c796b 100644
--- a/Lib/sqlite3/test/regression.py
+++ b/Lib/sqlite3/test/regression.py
@@ -132,6 +132,19 @@ def CheckTypeMapUsage(self):
         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 0000000000000..0571c2d110bee
--- /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 0000000000000..aecb0a1ea4d08
--- /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 26599b423eb8b..02e47a02b718c 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);



More information about the Python-checkins mailing list