8000 [3.12] gh-129603: Don't segfault if sqlite3.Row description is None (… · python/cpython@02e00a7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 02e00a7

Browse files
[3.12] gh-129603: Don't segfault if sqlite3.Row description is None (#129604) (#129924)
(cherry picked from commit 7e6ee50)
1 parent 23eccae commit 02e00a7

File tree

3 files changed

+83
-10
lines changed

3 files changed

+83
-10
lines changed

Lib/test/test_sqlite3/test_dbapi.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,5 +1955,70 @@ def wait():
19551955
self.assertEqual(proc.returncode, 0)
19561956

19571957

1958+
class RowTests(unittest.TestCase):
1959+
1960+
def setUp(self):
1961+
self.cx = sqlite.connect(":memory:")
1962+
self.cx.row_factory = sqlite.Row
1963+
1964+
def tearDown(self):
1965+
self.cx.close()
1966+
1967+
def test_row_keys(self):
1968+
cu = self.cx.execute("SELECT 1 as first, 2 as second")
1969+
row = cu.fetchone()
1970+
self.assertEqual(row.keys(), ["first", "second"])
1971+
1972+
def test_row_length(self):
1973+
cu = self.cx.execute("SELECT 1, 2, 3")
1974+
row = cu.fetchone()
1975+
self.assertEqual(len(row), 3)
1976+
1977+
def test_row_getitem(self):
1978+
cu = self.cx.execute("SELECT 1 as a, 2 as b")
1979+
row = cu.fetchone()
1980+
self.assertEqual(row[0], 1)
1981+
self.assertEqual(row[1], 2)
1982+
self.assertEqual(row["a"], 1)
1983+
self.assertEqual(row["b"], 2)
1984+
for key in "nokey", 4, 1.2:
1985+
with self.subTest(key=key):
1986+
with self.assertRaises(IndexError):
1987+
row[key]
1988+
1989+
def test_row_equality(self):
1990+
c1 = self.cx.execute("SELECT 1 as a")
1991+
r1 = c1.fetchone()
1992+
1993+
c2 = self.cx.execute("SELECT 1 as a")
1994+
r2 = c2.fetchone()
1995+
1996+
self.assertIsNot(r1, r2)
1997+
self.assertEqual(r1, r2)
1998+
1999+
c3 = self.cx.execute("SELECT 1 as b")
2000+
r3 = c3.fetchone()
2001+
2002+
self.assertNotEqual(r1, r3)
2003+
2004+
def test_row_no_description(self):
2005+
cu = self.cx.cursor()
2006+
self.assertIsNone(cu.description)
2007+
2008+
row = sqlite.Row(cu, ())
2009+
self.assertEqual(row.keys(), [])
2010+
with self.assertRaisesRegex(IndexError, "nokey"):
2011+
row["nokey"]
2012+
2013+
def test_row_is_a_sequence(self):
2014+
from collections.abc import Sequence
2015+
2016+
cu = self.cx.execute("SELECT 1")
2017+
row = cu.fetchone()
2018+
2019+
self.assertTrue(issubclass(sqlite.Row, Sequence))
2020+
self.assertTrue(isinstance(row, Sequence))
2021+
2022+
19582023
if __name__ == "__main__":
19592024
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix bugs where :class:`sqlite3.Row` objects could segfault if their
2+
inherited :attr:`~sqlite3.Cursor.description` was set to ``None``. Patch by
3+
Erlend Aasland.

Modules/_sqlite/row.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ static PyObject *
128128
pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
129129
{
130130
Py_ssize_t _idx;
131-
Py_ssize_t nitems, i;
132131

133132
if (PyLong_Check(idx)) {
134133
_idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
@@ -140,9 +139,13 @@ pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
140139
PyObject *item = PyTuple_GetItem(self->data, _idx);
141140
return Py_XNewRef(item);
142141
} else if (PyUnicode_Check(idx)) {
143-
nitems = PyTuple_Size(self->description);
142+
if (Py_IsNone(self->description)) {
143+
PyErr_Format(PyExc_IndexError, "No item with key %R", idx);
144+
return NULL;
145+
}
146+
Py_ssize_t nitems = PyTuple_GET_SIZE(self->description);
144147

145-
for (i = 0; i < nitems; i++) {
148+
for (Py_ssize_t i = 0; i < nitems; i++) {
146149
PyObject *obj;
147150
obj = PyTuple_GET_ITEM(self->description, i);
148151
obj = PyTuple_GET_ITEM(obj, 0);
@@ -185,17 +188,19 @@ static PyObject *
185188
pysqlite_row_keys_impl(pysqlite_Row *self)
186189
/*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/
187190
{
188-
PyObject* list;
189-
Py_ssize_t nitems, i;
190-
191-
list = PyList_New(0);
191+
PyObject *list = PyList_New(0);
192192
if (!list) {
193193
return NULL;
194194
}
195-
nitems = PyTuple_Size(self->description);
195+
if (Py_IsNone(self->description)) {
196+
return list;
197+
}
196198

197-
for (i = 0; i < nitems; i++) {
198-
if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
199+
Py_ssize_t nitems = PyTuple_GET_SIZE(self->description);
200+
for (Py_ssize_t i = 0; i < nitems; i++) {
201+
PyObject *descr = PyTuple_GET_ITEM(self->description, i);
202+
PyObject *name = PyTuple_GET_ITEM(descr, 0);
203+
if (PyList_Append(list, name) < 0) {
199204
Py_DECREF(list);
200205
return NULL;
201206
}

0 commit comments

Comments
 (0)
0