Skip to content

Commit 48e893e

Browse files
committed
gh-159739: Fix crash in _PyTuple_Resize() with an invalid size
_PyTuple_Resize() did not validate newsize for non-empty tuples. Raise SystemError for a negative size and MemoryError for a too-large size, like PyTuple_New() already does for the empty-tuple path.
1 parent b32a2ab commit 48e893e

3 files changed

Lines changed: 16 additions & 1 deletion

File tree

‎Lib/test/test_capi/test_tuple.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@ def test__tuple_resize(self):
327327
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX)
328328
self.assertRaises(SystemError, resize, a, -1)
329329
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN)
330+
a = ([1], [2], [3])
331+
self.assertRaises(MemoryError, resize, a, PY_SSIZE_T_MAX)
332+
self.assertRaises(SystemError, resize, a, -1)
333+
self.assertRaises(SystemError, resize, a, PY_SSIZE_T_MIN)
330334
# gh-159739: items are released if the reallocation fails
331335
x = object()
332336
refcnt = getrefcount(x)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a crash in :c:func:`_PyTuple_Resize` when resizing a non-empty tuple to a
2+
negative or too large size. It now raises :exc:`SystemError` or
3+
:exc:`MemoryError` respectively.

‎Objects/tupleobject.c‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
10211021
Py_ssize_t oldsize;
10221022

10231023
v = (PyTupleObject *) *pv;
1024-
if (v == NULL || !Py_IS_TYPE(v, &PyTuple_Type) ||
1024+
if (v == NULL || !Py_IS_TYPE(v, &PyTuple_Type) || newsize < 0 ||
10251025
(Py_SIZE(v) != 0 && !_PyObject_IsUniquelyReferenced(*pv))) {
10261026
*pv = 0;
10271027
Py_XDECREF(v);
@@ -1048,6 +1048,14 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
10481048
*pv = PyTuple_New(newsize);
10491049
return *pv == NULL ? -1 : 0;
10501050
}
1051+
/* Check for overflow */
1052+
if ((size_t)newsize > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) -
1053+
sizeof(PyObject *))) / sizeof(PyObject *)) {
1054+
*pv = NULL;
1055+
Py_DECREF(v);
1056+
PyErr_NoMemory();
1057+
return -1;
1058+
}
10511059

10521060
if (_PyObject_GC_IS_TRACKED(v)) {
10531061
_PyObject_GC_UNTRACK(v);

0 commit comments

Comments
 (0)