mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	gh-129603: Don't segfault if sqlite3.Row description is None (#129604)
This commit is contained in:
		
							parent
							
								
									d05053a203
								
							
						
					
					
						commit
						7e6ee50b6b
					
				
					 3 changed files with 83 additions and 10 deletions
				
			
		|  | @ -1924,5 +1924,70 @@ def wait(): | ||||||
|         self.assertEqual(proc.returncode, 0) |         self.assertEqual(proc.returncode, 0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class RowTests(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.cx = sqlite.connect(":memory:") | ||||||
|  |         self.cx.row_factory = sqlite.Row | ||||||
|  | 
 | ||||||
|  |     def tearDown(self): | ||||||
|  |         self.cx.close() | ||||||
|  | 
 | ||||||
|  |     def test_row_keys(self): | ||||||
|  |         cu = self.cx.execute("SELECT 1 as first, 2 as second") | ||||||
|  |         row = cu.fetchone() | ||||||
|  |         self.assertEqual(row.keys(), ["first", "second"]) | ||||||
|  | 
 | ||||||
|  |     def test_row_length(self): | ||||||
|  |         cu = self.cx.execute("SELECT 1, 2, 3") | ||||||
|  |         row = cu.fetchone() | ||||||
|  |         self.assertEqual(len(row), 3) | ||||||
|  | 
 | ||||||
|  |     def test_row_getitem(self): | ||||||
|  |         cu = self.cx.execute("SELECT 1 as a, 2 as b") | ||||||
|  |         row = cu.fetchone() | ||||||
|  |         self.assertEqual(row[0], 1) | ||||||
|  |         self.assertEqual(row[1], 2) | ||||||
|  |         self.assertEqual(row["a"], 1) | ||||||
|  |         self.assertEqual(row["b"], 2) | ||||||
|  |         for key in "nokey", 4, 1.2: | ||||||
|  |             with self.subTest(key=key): | ||||||
|  |                 with self.assertRaises(IndexError): | ||||||
|  |                     row[key] | ||||||
|  | 
 | ||||||
|  |     def test_row_equality(self): | ||||||
|  |         c1 = self.cx.execute("SELECT 1 as a") | ||||||
|  |         r1 = c1.fetchone() | ||||||
|  | 
 | ||||||
|  |         c2 = self.cx.execute("SELECT 1 as a") | ||||||
|  |         r2 = c2.fetchone() | ||||||
|  | 
 | ||||||
|  |         self.assertIsNot(r1, r2) | ||||||
|  |         self.assertEqual(r1, r2) | ||||||
|  | 
 | ||||||
|  |         c3 = self.cx.execute("SELECT 1 as b") | ||||||
|  |         r3 = c3.fetchone() | ||||||
|  | 
 | ||||||
|  |         self.assertNotEqual(r1, r3) | ||||||
|  | 
 | ||||||
|  |     def test_row_no_description(self): | ||||||
|  |         cu = self.cx.cursor() | ||||||
|  |         self.assertIsNone(cu.description) | ||||||
|  | 
 | ||||||
|  |         row = sqlite.Row(cu, ()) | ||||||
|  |         self.assertEqual(row.keys(), []) | ||||||
|  |         with self.assertRaisesRegex(IndexError, "nokey"): | ||||||
|  |             row["nokey"] | ||||||
|  | 
 | ||||||
|  |     def test_row_is_a_sequence(self): | ||||||
|  |         from collections.abc import Sequence | ||||||
|  | 
 | ||||||
|  |         cu = self.cx.execute("SELECT 1") | ||||||
|  |         row = cu.fetchone() | ||||||
|  | 
 | ||||||
|  |         self.assertIsSubclass(sqlite.Row, Sequence) | ||||||
|  |         self.assertIsInstance(row, Sequence) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     unittest.main() |     unittest.main() | ||||||
|  |  | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | Fix bugs where :class:`sqlite3.Row` objects could segfault if their | ||||||
|  | inherited :attr:`~sqlite3.Cursor.description` was set to ``None``. Patch by | ||||||
|  | Erlend Aasland. | ||||||
|  | @ -138,7 +138,6 @@ static PyObject * | ||||||
| pysqlite_row_subscript(PyObject *op, PyObject *idx) | pysqlite_row_subscript(PyObject *op, PyObject *idx) | ||||||
| { | { | ||||||
|     Py_ssize_t _idx; |     Py_ssize_t _idx; | ||||||
|     Py_ssize_t nitems, i; |  | ||||||
|     pysqlite_Row *self = _pysqlite_Row_CAST(op); |     pysqlite_Row *self = _pysqlite_Row_CAST(op); | ||||||
| 
 | 
 | ||||||
|     if (PyLong_Check(idx)) { |     if (PyLong_Check(idx)) { | ||||||
|  | @ -151,9 +150,13 @@ pysqlite_row_subscript(PyObject *op, PyObject *idx) | ||||||
|         PyObject *item = PyTuple_GetItem(self->data, _idx); |         PyObject *item = PyTuple_GetItem(self->data, _idx); | ||||||
|         return Py_XNewRef(item); |         return Py_XNewRef(item); | ||||||
|     } else if (PyUnicode_Check(idx)) { |     } else if (PyUnicode_Check(idx)) { | ||||||
|         nitems = PyTuple_Size(self->description); |         if (Py_IsNone(self->description)) { | ||||||
|  |             PyErr_Format(PyExc_IndexError, "No item with key %R", idx); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         Py_ssize_t nitems = PyTuple_GET_SIZE(self->description); | ||||||
| 
 | 
 | ||||||
|         for (i = 0; i < nitems; i++) { |         for (Py_ssize_t i = 0; i < nitems; i++) { | ||||||
|             PyObject *obj; |             PyObject *obj; | ||||||
|             obj = PyTuple_GET_ITEM(self->description, i); |             obj = PyTuple_GET_ITEM(self->description, i); | ||||||
|             obj = PyTuple_GET_ITEM(obj, 0); |             obj = PyTuple_GET_ITEM(obj, 0); | ||||||
|  | @ -197,17 +200,19 @@ static PyObject * | ||||||
| pysqlite_row_keys_impl(pysqlite_Row *self) | pysqlite_row_keys_impl(pysqlite_Row *self) | ||||||
| /*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/ | /*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/ | ||||||
| { | { | ||||||
|     PyObject* list; |     PyObject *list = PyList_New(0); | ||||||
|     Py_ssize_t nitems, i; |  | ||||||
| 
 |  | ||||||
|     list = PyList_New(0); |  | ||||||
|     if (!list) { |     if (!list) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     nitems = PyTuple_Size(self->description); |     if (Py_IsNone(self->description)) { | ||||||
|  |         return list; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     for (i = 0; i < nitems; i++) { |     Py_ssize_t nitems = PyTuple_GET_SIZE(self->description); | ||||||
|         if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { |     for (Py_ssize_t i = 0; i < nitems; i++) { | ||||||
|  |         PyObject *descr = PyTuple_GET_ITEM(self->description, i); | ||||||
|  |         PyObject *name = PyTuple_GET_ITEM(descr, 0); | ||||||
|  |         if (PyList_Append(list, name) < 0) { | ||||||
|             Py_DECREF(list); |             Py_DECREF(list); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Erlend E. Aasland
						Erlend E. Aasland