]> granicus.if.org Git - python/commitdiff
bpo-38175: Fix a memory leak in comparison of sqlite3.Row objects. (GH-16155)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 16 Sep 2019 17:15:18 +0000 (20:15 +0300)
committerGitHub <noreply@github.com>
Mon, 16 Sep 2019 17:15:18 +0000 (20:15 +0300)
Lib/sqlite3/test/factory.py
Misc/NEWS.d/next/Library/2019-09-15-10-30-33.bpo-38175.61XlUv.rst [new file with mode: 0644]
Modules/_sqlite/row.c

index ced8445536e3c69ddabf9283aaa62d546e859e2a..f103211ed9f19588aecccf4007a560556c1ecd16 100644 (file)
@@ -169,19 +169,33 @@ class RowFactoryTests(unittest.TestCase):
         row_1 = self.con.execute("select 1 as a, 2 as b").fetchone()
         row_2 = self.con.execute("select 1 as a, 2 as b").fetchone()
         row_3 = self.con.execute("select 1 as a, 3 as b").fetchone()
+        row_4 = self.con.execute("select 1 as b, 2 as a").fetchone()
+        row_5 = self.con.execute("select 2 as b, 1 as a").fetchone()
 
-        self.assertEqual(row_1, row_1)
-        self.assertEqual(row_1, row_2)
-        self.assertTrue(row_2 != row_3)
+        self.assertTrue(row_1 == row_1)
+        self.assertTrue(row_1 == row_2)
+        self.assertFalse(row_1 == row_3)
+        self.assertFalse(row_1 == row_4)
+        self.assertFalse(row_1 == row_5)
+        self.assertFalse(row_1 == object())
 
         self.assertFalse(row_1 != row_1)
         self.assertFalse(row_1 != row_2)
-        self.assertFalse(row_2 == row_3)
+        self.assertTrue(row_1 != row_3)
+        self.assertTrue(row_1 != row_4)
+        self.assertTrue(row_1 != row_5)
+        self.assertTrue(row_1 != object())
+
+        with self.assertRaises(TypeError):
+            row_1 > row_2
+        with self.assertRaises(TypeError):
+            row_1 < row_2
+        with self.assertRaises(TypeError):
+            row_1 >= row_2
+        with self.assertRaises(TypeError):
+            row_1 <= row_2
 
-        self.assertEqual(row_1, row_2)
         self.assertEqual(hash(row_1), hash(row_2))
-        self.assertNotEqual(row_1, row_3)
-        self.assertNotEqual(hash(row_1), hash(row_3))
 
     def CheckSqliteRowAsSequence(self):
         """ Checks if the row object can act like a sequence """
diff --git a/Misc/NEWS.d/next/Library/2019-09-15-10-30-33.bpo-38175.61XlUv.rst b/Misc/NEWS.d/next/Library/2019-09-15-10-30-33.bpo-38175.61XlUv.rst
new file mode 100644 (file)
index 0000000..6d9f280
--- /dev/null
@@ -0,0 +1 @@
+Fix a memory leak in comparison of :class:`sqlite3.Row` objects.
index 5c2f40082402e3080514b0f17e882a5ee0d7b017..758518a8ff80be4c724ee1bfb766af5f021e339c 100644 (file)
@@ -192,14 +192,16 @@ static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other,
     if (opid != Py_EQ && opid != Py_NE)
         Py_RETURN_NOTIMPLEMENTED;
 
-    if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) {
+    if (PyObject_TypeCheck(_other, &pysqlite_RowType)) {
         pysqlite_Row *other = (pysqlite_Row *)_other;
-        PyObject *res = PyObject_RichCompare(self->description, other->description, opid);
-        if ((opid == Py_EQ && res == Py_True)
-            || (opid == Py_NE && res == Py_False)) {
-            Py_DECREF(res);
+        int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ);
+        if (eq < 0) {
+            return NULL;
+        }
+        if (eq) {
             return PyObject_RichCompare(self->data, other->data, opid);
         }
+        return PyBool_FromLong(opid != Py_EQ);
     }
     Py_RETURN_NOTIMPLEMENTED;
 }