|
8 | 8 | from test.support import import_helper |
9 | 9 | from test.support import os_helper |
10 | 10 | from test.support import _2G |
| 11 | +from test.support import subTests |
11 | 12 | import weakref |
12 | 13 | import pickle |
13 | 14 | import operator |
@@ -1680,63 +1681,60 @@ def test_gh_128961(self): |
1680 | 1681 | it.__setstate__(0) |
1681 | 1682 | self.assertRaises(StopIteration, next, it) |
1682 | 1683 |
|
1683 | | - def test_array_validity_after_call_user_method(self): |
| 1684 | + @subTests( |
| 1685 | + ("dtype", "items"), |
| 1686 | + [ |
| 1687 | + ("b", [0] * 64), |
| 1688 | + ("B", [1, 2, 3]), |
| 1689 | + ("h", [1, 2, 3]), |
| 1690 | + ("H", [1, 2, 3]), |
| 1691 | + ("i", [1, 2, 3]), |
| 1692 | + ("l", [1, 2, 3]), |
| 1693 | + ("q", [1, 2, 3]), |
| 1694 | + ("I", [1, 2, 3]), |
| 1695 | + ("L", [1, 2, 3]), |
| 1696 | + ("Q", [1, 2, 3]), |
| 1697 | + ], |
| 1698 | + ) |
| 1699 | + def test_setitem_use_after_clear_with_int_data(self, dtype, items): |
1684 | 1700 | # gh-142555: Test for null pointer dereference in array.__setitem__ |
1685 | | - # via re-entrant __index__ or __float__. |
1686 | | - |
1687 | | - def test_clear_array(victim): |
1688 | | - class EvilIndex: |
1689 | | - def __index__(self): |
1690 | | - # Re-entrant mutation: clear the array while __setitem__ |
1691 | | - # still holds a pointer to the pre-clear buffer. |
1692 | | - victim.clear() |
1693 | | - return 0 |
1694 | | - |
1695 | | - with self.assertRaises(IndexError): |
1696 | | - victim[1] = EvilIndex() |
1697 | | - |
1698 | | - self.assertEqual(len(victim), 0) |
1699 | | - |
1700 | | - def test_shrink_array(victim): |
1701 | | - class ShrinkIndex: |
1702 | | - def __index__(self): |
1703 | | - # Re-entrant mutation: change the array size while |
1704 | | - # __setitem__ still keep the original size. |
1705 | | - victim.pop() |
1706 | | - victim.pop() |
1707 | | - return 0 |
1708 | | - |
1709 | | - with self.assertRaises(IndexError): |
1710 | | - victim[1] = ShrinkIndex() |
1711 | | - |
1712 | | - test_clear_array(array.array('b', [0] * 64)) |
1713 | | - test_shrink_array(array.array('b', [1, 2, 3])) |
1714 | | - test_clear_array(array.array('B', [1, 2, 3])) |
1715 | | - test_clear_array(array.array('h', [1, 2, 3])) |
1716 | | - test_clear_array(array.array('H', [1, 2, 3])) |
1717 | | - test_clear_array(array.array('i', [1, 2, 3])) |
1718 | | - test_clear_array(array.array('l', [1, 2, 3])) |
1719 | | - test_clear_array(array.array('q', [1, 2, 3])) |
1720 | | - test_clear_array(array.array('I', [1, 2, 3])) |
1721 | | - test_clear_array(array.array('L', [1, 2, 3])) |
1722 | | - test_clear_array(array.array('Q', [1, 2, 3])) |
1723 | | - |
1724 | | - def test_clear_array_float(victim): |
1725 | | - """Test array clearing scenario using __float__ method""" |
1726 | | - class EvilFloat: |
1727 | | - def __float__(self): |
1728 | | - # Re-entrant mutation: clear the array while __setitem__ |
1729 | | - # still holds a pointer to the pre-clear buffer. |
1730 | | - victim.clear() |
1731 | | - return 0.0 |
1732 | | - |
1733 | | - with self.assertRaises(IndexError): |
1734 | | - victim[1] = EvilFloat() |
1735 | | - |
1736 | | - self.assertEqual(len(victim), 0) |
1737 | | - |
1738 | | - test_clear_array_float(array.array('f', [1.0, 2.0, 3.0])) |
1739 | | - test_clear_array_float(array.array('d', [1.0, 2.0, 3.0])) |
| 1701 | + # via re-entrant __index__ that clears the array. |
| 1702 | + victim = array.array(dtype, items) |
| 1703 | + |
| 1704 | + class Index: |
| 1705 | + def __index__(self): |
| 1706 | + victim.clear() |
| 1707 | + return 0 |
| 1708 | + |
| 1709 | + self.assertRaises(IndexError, victim.__setitem__, 1, Index()) |
| 1710 | + self.assertEqual(len(victim), 0) |
| 1711 | + |
| 1712 | + def test_setitem_use_after_shrink_with_int_data(self): |
| 1713 | + # gh-142555: Test for null pointer dereference in array.__setitem__ |
| 1714 | + # via re-entrant __index__ that shrinks the array. |
| 1715 | + victim = array.array('b', [1, 2, 3]) |
| 1716 | + |
| 1717 | + class Index: |
| 1718 | + def __index__(self): |
| 1719 | + victim.pop() |
| 1720 | + victim.pop() |
| 1721 | + return 0 |
| 1722 | + |
| 1723 | + self.assertRaises(IndexError, victim.__setitem__, 1, Index()) |
| 1724 | + |
| 1725 | + @subTests("dtype", ["f", "d"]) |
| 1726 | + def test_setitem_use_after_clear_with_float_data(self, dtype): |
| 1727 | + # gh-142555: Test for null pointer dereference in array.__setitem__ |
| 1728 | + # via re-entrant __float__ that clears the array. |
| 1729 | + victim = array.array(dtype, [1.0, 2.0, 3.0]) |
| 1730 | + |
| 1731 | + class Float: |
| 1732 | + def __float__(self): |
| 1733 | + victim.clear() |
| 1734 | + return 0.0 |
| 1735 | + |
| 1736 | + self.assertRaises(IndexError, victim.__setitem__, 1, Float()) |
| 1737 | + self.assertEqual(len(victim), 0) |
1740 | 1738 |
|
1741 | 1739 |
|
1742 | 1740 | if __name__ == "__main__": |
|
0 commit comments