[Python-checkins] gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bit builds (#103902)

erlend-aasland webhook-mailer at python.org
Sun May 7 06:55:38 EDT 2023


https://github.com/python/cpython/commit/a05bad3254e2ae5fdf558dfdb65899a2298d8ded
commit: a05bad3254e2ae5fdf558dfdb65899a2298d8ded
branch: main
author: Erlend E. Aasland <erlend.aasland at protonmail.com>
committer: erlend-aasland <erlend.aasland at protonmail.com>
date: 2023-05-07T12:55:31+02:00
summary:

gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bit builds (#103902)

files:
A Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst
M Lib/test/test_sqlite3/test_dbapi.py
M Modules/_sqlite/clinic/connection.c.h
M Modules/_sqlite/connection.c

diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py
index 1bb0e13e356e..328b0467e7fa 100644
--- a/Lib/test/test_sqlite3/test_dbapi.py
+++ b/Lib/test/test_sqlite3/test_dbapi.py
@@ -1495,6 +1495,14 @@ def test_blob_closed_db_read(self):
                                    "Cannot operate on a closed database",
                                    blob.read)
 
+    def test_blob_32bit_rowid(self):
+        # gh-100370: we should not get an OverflowError for 32-bit rowids
+        with memory_database() as cx:
+            rowid = 2**32
+            cx.execute("create table t(t blob)")
+            cx.execute("insert into t(rowid, t) values (?, zeroblob(1))", (rowid,))
+            cx.blobopen('t', 't', rowid)
+
 
 @threading_helper.requires_working_threading()
 class ThreadTests(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst
new file mode 100644
index 000000000000..9022d55c48cb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst
@@ -0,0 +1,2 @@
+Fix potential :exc:`OverflowError` in :meth:`sqlite3.Connection.blobopen`
+for 32-bit builds. Patch by Erlend E. Aasland.
diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h
index 182754cca36d..417abcc46261 100644
--- a/Modules/_sqlite/clinic/connection.c.h
+++ b/Modules/_sqlite/clinic/connection.c.h
@@ -228,7 +228,7 @@ PyDoc_STRVAR(blobopen__doc__,
 
 static PyObject *
 blobopen_impl(pysqlite_Connection *self, const char *table, const char *col,
-              int row, int readonly, const char *name);
+              sqlite3_int64 row, int readonly, const char *name);
 
 static PyObject *
 blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -263,7 +263,7 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO
     Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3;
     const char *table;
     const char *col;
-    int row;
+    sqlite3_int64 row;
     int readonly = 0;
     const char *name = "main";
 
@@ -297,8 +297,7 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO
         PyErr_SetString(PyExc_ValueError, "embedded null character");
         goto exit;
     }
-    row = _PyLong_AsInt(args[2]);
-    if (row == -1 && PyErr_Occurred()) {
+    if (!sqlite3_int64_converter(args[2], &row)) {
         goto exit;
     }
     if (!noptargs) {
@@ -1666,4 +1665,4 @@ getconfig(pysqlite_Connection *self, PyObject *arg)
 #ifndef DESERIALIZE_METHODDEF
     #define DESERIALIZE_METHODDEF
 #endif /* !defined(DESERIALIZE_METHODDEF) */
-/*[clinic end generated code: output=8b03149c115ee6da input=a9049054013a1b77]*/
+/*[clinic end generated code: output=834a99827555bf1a input=a9049054013a1b77]*/
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index aec3aa8bbf4e..7bbb462ed54d 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -118,6 +118,20 @@ autocommit_converter(PyObject *val, enum autocommit_mode *result)
     return 0;
 }
 
+static int
+sqlite3_int64_converter(PyObject *obj, sqlite3_int64 *result)
+{
+    if (!PyLong_Check(obj)) {
+        PyErr_SetString(PyExc_TypeError, "expected 'int'");
+        return 0;
+    }
+    *result = _pysqlite_long_as_int64(obj);
+    if (PyErr_Occurred()) {
+        return 0;
+    }
+    return 1;
+}
+
 #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
 #include "clinic/connection.c.h"
 #undef clinic_state
@@ -188,8 +202,12 @@ class Autocommit_converter(CConverter):
     type = "enum autocommit_mode"
     converter = "autocommit_converter"
 
+class sqlite3_int64_converter(CConverter):
+    type = "sqlite3_int64"
+    converter = "sqlite3_int64_converter"
+
 [python start generated code]*/
-/*[python end generated code: output=da39a3ee5e6b4b0d input=bc2aa6c7ba0c5f8f]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=dff8760fb1eba6a1]*/
 
 // NB: This needs to be in sync with the sqlite3.connect docstring
 /*[clinic input]
@@ -483,7 +501,7 @@ _sqlite3.Connection.blobopen as blobopen
         Table name.
     column as col: str
         Column name.
-    row: int
+    row: sqlite3_int64
         Row index.
     /
     *
@@ -497,8 +515,8 @@ Open and return a BLOB object.
 
 static PyObject *
 blobopen_impl(pysqlite_Connection *self, const char *table, const char *col,
-              int row, int readonly, const char *name)
-/*[clinic end generated code: output=0c8e2e58516d0b5c input=fa73c83aa7a7ddee]*/
+              sqlite3_int64 row, int readonly, const char *name)
+/*[clinic end generated code: output=6a02d43efb885d1c input=23576bd1108d8774]*/
 {
     if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
         return NULL;



More information about the Python-checkins mailing list