diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index ba9c25c835bc39..943420f4c3f4e8 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1612,6 +1612,13 @@ def test_overflows(self): self.assertRaises(OverflowError, array.array, self.typecode, [123456]) # Overflows also float type: self.assertRaises(OverflowError, array.array, self.typecode, [1e300]) + # A failed append, insert or extend leaves the array unchanged: + for x in 123456, 1e300: + a = array.array(self.typecode, [1]) + self.assertRaises(OverflowError, a.append, x) + self.assertRaises(OverflowError, a.insert, 0, x) + self.assertRaises(OverflowError, a.extend, [x]) + self.assertEqual(a, array.array(self.typecode, [1])) class FloatTest(FPTest, unittest.TestCase): typecode = 'f' @@ -1619,6 +1626,12 @@ class FloatTest(FPTest, unittest.TestCase): def test_overflows(self): self.assertRaises(OverflowError, array.array, self.typecode, [1e300]) + # A failed append, insert or extend leaves the array unchanged: + a = array.array(self.typecode, [1]) + self.assertRaises(OverflowError, a.append, 1e300) + self.assertRaises(OverflowError, a.insert, 0, 1e300) + self.assertRaises(OverflowError, a.extend, [1e300]) + self.assertEqual(a, array.array(self.typecode, [1])) class DoubleTest(FPTest, unittest.TestCase): typecode = 'd' @@ -1649,6 +1662,13 @@ class ComplexFloatTest(CFPTest, unittest.TestCase): def test_overflows(self): self.assertRaises(OverflowError, array.array, self.typecode, [1e300]) self.assertRaises(OverflowError, array.array, self.typecode, [1e300j]) + # A failed append, insert or extend leaves the array unchanged: + for x in 1e300, 1e300j: + a = array.array(self.typecode, [1]) + self.assertRaises(OverflowError, a.append, x) + self.assertRaises(OverflowError, a.insert, 0, x) + self.assertRaises(OverflowError, a.extend, [x]) + self.assertEqual(a, array.array(self.typecode, [1])) class ComplexDoubleTest(CFPTest, unittest.TestCase): typecode = 'Zd' diff --git a/Misc/NEWS.d/next/Library/2026-09-28-13-52-36.gh-issue-158345.GNlDCF.rst b/Misc/NEWS.d/next/Library/2026-09-28-13-52-36.gh-issue-158345.GNlDCF.rst new file mode 100644 index 00000000000000..208b3e8055e54a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-28-13-52-36.gh-issue-158345.GNlDCF.rst @@ -0,0 +1,3 @@ +Fix :meth:`array.array.append`, :meth:`~array.array.insert` and +:meth:`~array.array.extend` leaving an extra item in the array when they +raise :exc:`OverflowError` for the ``'e'``, ``'f'`` or ``'Zf'`` type code. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index ef492d143d5644..fee9ba3d6debf2 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -823,6 +823,8 @@ getarrayitem(PyObject *op, Py_ssize_t i) return (*ap->ob_descr->getitem)(ap, i); } +static int array_del_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh); + static int ins1(arrayobject *self, Py_ssize_t where, PyObject *v) { @@ -832,8 +834,6 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v) PyErr_BadInternalCall(); return -1; } - if ((*self->ob_descr->setitem)(self, -1, v) < 0) - return -1; if (array_resize(self, n+1) == -1) return -1; @@ -850,7 +850,11 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v) memmove(items + (where+1)*self->ob_descr->itemsize, items + where*self->ob_descr->itemsize, (n-where)*self->ob_descr->itemsize); - return (*self->ob_descr->setitem)(self, where, v); + if ((*self->ob_descr->setitem)(self, where, v) < 0) { + array_del_slice(self, where, where+1); + return -1; + } + return 0; } /* Methods */