Skip to content

Commit d6daeee

Browse files
[3.13] gh-129603: Don't segfault if sqlite3.Row description is None (#129604) (#129923)
(cherry picked from commit 7e6ee50)
1 parent d26c2fe commit d6daeee

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
@@ -1947,5 +1947,70 @@ def wait():
19471947
self.assertEqual(proc.returncode, 0)
19481948

19491949

1950+
class RowTests(unittest.TestCase):
1951+
1952+
def setUp(self):
1953+
self.cx = sqlite.connect(":memory:")
1954+
self.cx.row_factory = sqlite.Row
1955+
1956+
def tearDown(self):
1957+
self.cx.close()
1958+
1959+
def test_row_keys(self):
1960+
cu = self.cx.execute("SELECT 1 as first, 2 as second")
1961+
row = cu.fetchone()
1962+
self.assertEqual(row.keys(), ["first", "second"])
1963+
1964+
def test_row_length(self):
1965+
cu = self.cx.execute("SELECT 1, 2, 3")
1966+
row = cu.fetchone()
1967+
self.assertEqual(len(row), 3)
1968+
1969+
def test_row_getitem(self):
1970+
cu = self.cx.execute("SELECT 1 as a, 2 as b")
1971+
row = cu.fetchone()
1972+
self.assertEqual(row[0], 1)
1973+
self.assertEqual(row[1], 2)
1974+
self.assertEqual(row["a"], 1)
1975+
self.assertEqual(row["b"], 2)
1976+
for key in "nokey", 4, 1.2:
1977+
with self.subTest(key=key):
1978+
with self.assertRaises(IndexError):
1979+
row[key]
1980+
1981+
def test_row_equality(self):
1982+
c1 = self.cx.execute("SELECT 1 as a")
1983+
r1 = c1.fetchone()
1984+
1985+
c2 = self.cx.execute("SELECT 1 as a")
1986+
r2 = c2.fetchone()
1987+
1988+
self.assertIsNot(r1, r2)
1989+
self.assertEqual(r1, r2)
1990+
1991+
c3 = self.cx.execute("SELECT 1 as b")
1992+
r3 = c3.fetchone()
1993+
1994+
self.assertNotEqual(r1, r3)
1995+
1996+
def test_row_no_description(self):
1997+
cu = self.cx.cursor()
1998+
self.assertIsNone(cu.description)
1999+
2000+
row = sqlite.Row(cu, ())
2001+
self.assertEqual(row.keys(), [])
2002+
with self.assertRaisesRegex(IndexError, "nokey"):
2003+
row["nokey"]
2004+
2005+
def test_row_is_a_sequence(self):
2006+
from collections.abc import Sequence
2007+
2008+
cu = self.cx.execute("SELECT 1")
2009+
row = cu.fetchone()
2010+
2011+
self.assertTrue(issubclass(sqlite.Row, Sequence))
2012+
self.assertTrue(isinstance(row, Sequence))
2013+
2014+
19502015
if __name__ == "__main__":
19512016
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
@@ -132,7 +132,6 @@ static PyObject *
132132
pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
133133
{
134134
Py_ssize_t _idx;
135-
Py_ssize_t nitems, i;
136135

137136
if (PyLong_Check(idx)) {
138137
_idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
@@ -144,9 +143,13 @@ pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
144143
PyObject *item = PyTuple_GetItem(self->data, _idx);
145144
return Py_XNewRef(item);
146145
} else if (PyUnicode_Check(idx)) {
147-
nitems = PyTuple_Size(self->description);
146+
if (Py_IsNone(self->description)) {
147+
PyErr_Format(PyExc_IndexError, "No item with key %R", idx);
148+
return NULL;
149+
}
150+
Py_ssize_t nitems = PyTuple_GET_SIZE(self->description);
148151

149-
for (i = 0; i < nitems; i++) {
152+
for (Py_ssize_t i = 0; i < nitems; i++) {
150153
PyObject *obj;
151154
obj = PyTuple_GET_ITEM(self->description, i);
152155
obj = PyTuple_GET_ITEM(obj, 0);
@@ -189,17 +192,19 @@ static PyObject *
189192
pysqlite_row_keys_impl(pysqlite_Row *self)
190193
/*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/
191194
{
192-
PyObject* list;
193-
Py_ssize_t nitems, i;
194-
195-
list = PyList_New(0);
195+
PyObject *list = PyList_New(0);
196196
if (!list) {
197197
return NULL;
198198
}
199-
nitems = PyTuple_Size(self->description);
199+
if (Py_IsNone(self->description)) {
200+
return list;
201+
}
200202

201-
for (i = 0; i < nitems; i++) {
202-
if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
203+
Py_ssize_t nitems = PyTuple_GET_SIZE(self->description);
204+
for (Py_ssize_t i = 0; i < nitems; i++) {
205+
PyObject *descr = PyTuple_GET_ITEM(self->description, i);
206+
PyObject *name = PyTuple_GET_ITEM(descr, 0);
207+
if (PyList_Append(list, name) < 0) {
203208
Py_DECREF(list);
204209
return NULL;
205210
}

0 commit comments

Comments
 (0)