[Python-checkins] bpo-43369: sqlite3_column_{text, blob} failures now raise MemoryError (GH-24723)

berkerpeksag webhook-mailer at python.org
Thu Mar 4 04:50:40 EST 2021


https://github.com/python/cpython/commit/e161ec5dd7ba9355eb06757b9304019ac53cdf69
commit: e161ec5dd7ba9355eb06757b9304019ac53cdf69
branch: master
author: Erlend Egeberg Aasland <erlend.aasland at innova.no>
committer: berkerpeksag <berker.peksag at gmail.com>
date: 2021-03-04T11:50:25+02:00
summary:

bpo-43369: sqlite3_column_{text,blob} failures now raise MemoryError (GH-24723)

files:
A Misc/NEWS.d/next/Library/2021-03-02-15-25-28.bpo-43369.F4knlQ.rst
M Lib/sqlite3/test/types.py
M Modules/_sqlite/cursor.c

diff --git a/Lib/sqlite3/test/types.py b/Lib/sqlite3/test/types.py
index 92ec6349f8bd2..2370dd1693042 100644
--- a/Lib/sqlite3/test/types.py
+++ b/Lib/sqlite3/test/types.py
@@ -110,7 +110,20 @@ def __conform__(self, protocol):
     def setUp(self):
         self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
         self.cur = self.con.cursor()
-        self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob, n1 number, n2 number(5), bad bad)")
+        self.cur.execute("""
+            create table test(
+                i int,
+                s str,
+                f float,
+                b bool,
+                u unicode,
+                foo foo,
+                bin blob,
+                n1 number,
+                n2 number(5),
+                bad bad,
+                cbin cblob)
+        """)
 
         # override float, make them always return the same number
         sqlite.converters["FLOAT"] = lambda x: 47.2
@@ -121,6 +134,7 @@ def setUp(self):
         sqlite.converters["BAD"] = DeclTypesTests.BadConform
         sqlite.converters["WRONG"] = lambda x: "WRONG"
         sqlite.converters["NUMBER"] = float
+        sqlite.converters["CBLOB"] = lambda x: b"blobish"
 
     def tearDown(self):
         del sqlite.converters["FLOAT"]
@@ -129,6 +143,7 @@ def tearDown(self):
         del sqlite.converters["BAD"]
         del sqlite.converters["WRONG"]
         del sqlite.converters["NUMBER"]
+        del sqlite.converters["CBLOB"]
         self.cur.close()
         self.con.close()
 
@@ -237,6 +252,12 @@ def test_number2(self):
         # if the converter is not used, it's an int instead of a float
         self.assertEqual(type(value), float)
 
+    def test_convert_zero_sized_blob(self):
+        self.con.execute("insert into test(cbin) values (?)", (b"",))
+        cur = self.con.execute("select cbin from test")
+        self.assertEqual(cur.fetchone()[0], b"blobish")
+
+
 class ColNamesTests(unittest.TestCase):
     def setUp(self):
         self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
diff --git a/Misc/NEWS.d/next/Library/2021-03-02-15-25-28.bpo-43369.F4knlQ.rst b/Misc/NEWS.d/next/Library/2021-03-02-15-25-28.bpo-43369.F4knlQ.rst
new file mode 100644
index 0000000000000..f88a7070dbcee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-03-02-15-25-28.bpo-43369.F4knlQ.rst
@@ -0,0 +1,3 @@
+Improve :mod:`sqlite3` error handling: If ``sqlite3_column_text()`` and
+``sqlite3_column_blob()`` set ``SQLITE_NOMEM``, :exc:`MemoryError` is now
+raised. Patch by Erlend E. Aasland.
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 764eec5fbcac6..dfaa5577ab408 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -262,6 +262,7 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
     if (!row)
         return NULL;
 
+    sqlite3 *db = self->connection->db;
     for (i = 0; i < numcols; i++) {
         if (self->connection->detect_types
                 && self->row_cast_map != NULL
@@ -280,17 +281,19 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
          * See https://sqlite.org/c3ref/column_blob.html for details.
          */
         if (converter != Py_None) {
-            const char *blob = (const char*)sqlite3_column_blob(self->statement->st, i);
+            const void *blob = sqlite3_column_blob(self->statement->st, i);
+            if (blob == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
+                PyErr_NoMemory();
+                goto error;
+            }
+
             nbytes = sqlite3_column_bytes(self->statement->st, i);
-            if (!blob) {
-                converted = Py_NewRef(Py_None);
-            } else {
-                item = PyBytes_FromStringAndSize(blob, nbytes);
-                if (!item)
-                    goto error;
-                converted = PyObject_CallOneArg(converter, item);
-                Py_DECREF(item);
+            item = PyBytes_FromStringAndSize(blob, nbytes);
+            if (item == NULL) {
+                goto error;
             }
+            converted = PyObject_CallOneArg(converter, item);
+            Py_DECREF(item);
         } else {
             Py_BEGIN_ALLOW_THREADS
             coltype = sqlite3_column_type(self->statement->st, i);
@@ -303,6 +306,11 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
                 converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i));
             } else if (coltype == SQLITE_TEXT) {
                 const char *text = (const char*)sqlite3_column_text(self->statement->st, i);
+                if (text == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
+                    PyErr_NoMemory();
+                    goto error;
+                }
+
                 nbytes = sqlite3_column_bytes(self->statement->st, i);
                 if (self->connection->text_factory == (PyObject*)&PyUnicode_Type) {
                     converted = PyUnicode_FromStringAndSize(text, nbytes);
@@ -332,7 +340,12 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
                 }
             } else {
                 /* coltype == SQLITE_BLOB */
-                const char *blob = sqlite3_column_blob(self->statement->st, i);
+                const void *blob = sqlite3_column_blob(self->statement->st, i);
+                if (blob == NULL && sqlite3_errcode(db) == SQLITE_NOMEM) {
+                    PyErr_NoMemory();
+                    goto error;
+                }
+
                 nbytes = sqlite3_column_bytes(self->statement->st, i);
                 converted = PyBytes_FromStringAndSize(blob, nbytes);
             }



More information about the Python-checkins mailing list