Skip to content

Commit

Permalink
gh-111495: Test C API functions with extreme sizes and indices (GH-11…
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiy-storchaka committed Nov 4, 2023
1 parent f48e669 commit a8e1f47
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 40 deletions.
54 changes: 35 additions & 19 deletions Lib/test/test_capi/test_abstract.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import unittest
from collections import OrderedDict
import _testcapi
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX

NULL = None

Expand Down Expand Up @@ -574,6 +576,8 @@ def test_sequence_getitem(self):
self.assertEqual(getitem(lst, 1), 'b')
self.assertEqual(getitem(lst, -1), 'c')
self.assertRaises(IndexError, getitem, lst, 3)
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MAX)
self.assertRaises(IndexError, getitem, lst, PY_SSIZE_T_MIN)

self.assertRaises(TypeError, getitem, 42, 1)
self.assertRaises(TypeError, getitem, {}, 1)
Expand All @@ -598,6 +602,9 @@ def test_sequence_repeat(self):
self.assertEqual(repeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
self.assertEqual(repeat(['a', 'b'], 0), [])
self.assertEqual(repeat(['a', 'b'], -1), [])
self.assertEqual(repeat(['a', 'b'], PY_SSIZE_T_MIN), [])
self.assertEqual(repeat([], PY_SSIZE_T_MAX), [])
self.assertRaises(MemoryError, repeat, ['a', 'b'], PY_SSIZE_T_MAX)

self.assertRaises(TypeError, repeat, set(), 2)
self.assertRaises(TypeError, repeat, 42, 2)
Expand Down Expand Up @@ -631,6 +638,9 @@ def test_sequence_inplacerepeat(self):
self.assertEqual(inplacerepeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
self.assertEqual(inplacerepeat(['a', 'b'], 0), [])
self.assertEqual(inplacerepeat(['a', 'b'], -1), [])
self.assertEqual(inplacerepeat(['a', 'b'], PY_SSIZE_T_MIN), [])
self.assertEqual(inplacerepeat([], PY_SSIZE_T_MAX), [])
self.assertRaises(MemoryError, inplacerepeat, ['a', 'b'], PY_SSIZE_T_MAX)

self.assertRaises(TypeError, inplacerepeat, set(), 2)
self.assertRaises(TypeError, inplacerepeat, 42, 2)
Expand All @@ -647,6 +657,8 @@ def test_sequence_setitem(self):
setitem(lst, 0, NULL)
self.assertEqual(lst, ['x', 'y'])
self.assertRaises(IndexError, setitem, lst, 3, 'x')
self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MAX, 'x')
self.assertRaises(IndexError, setitem, lst, PY_SSIZE_T_MIN, 'x')

self.assertRaises(TypeError, setitem, 42, 1, 'x')
self.assertRaises(TypeError, setitem, {}, 1, 'x')
Expand All @@ -660,6 +672,8 @@ def test_sequence_delitem(self):
delitem(lst, -1)
self.assertEqual(lst, ['a'])
self.assertRaises(IndexError, delitem, lst, 3)
self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MAX)
self.assertRaises(IndexError, delitem, lst, PY_SSIZE_T_MIN)

self.assertRaises(TypeError, delitem, 42, 1)
self.assertRaises(TypeError, delitem, {}, 1)
Expand All @@ -669,13 +683,19 @@ def test_sequence_setslice(self):
setslice = _testcapi.sequence_setslice

# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()

setslice(data, 1, 3, [8, 9])
data_copy[1:3] = [8, 9]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 8, 9, 4, 5])
for start in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
for stop in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
data = [1, 2, 3, 4, 5]
data_copy = [1, 2, 3, 4, 5]
setslice(data, start, stop, [8, 9])
data_copy[start:stop] = [8, 9]
self.assertEqual(data, data_copy)

data = [1, 2, 3, 4, 5]
data_copy = [1, 2, 3, 4, 5]
setslice(data, start, stop, NULL)
del data_copy[start:stop]
self.assertEqual(data, data_copy)

# Custom class:
class Custom:
Expand All @@ -701,21 +721,17 @@ def __setitem__(self, index, value):
self.assertRaises(TypeError, setslice, object(), 1, 3, 'xy')
self.assertRaises(SystemError, setslice, NULL, 1, 3, 'xy')

data_copy = data.copy()
setslice(data_copy, 1, 3, NULL)
self.assertEqual(data_copy, [1, 4, 5])

def test_sequence_delslice(self):
delslice = _testcapi.sequence_delslice

# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()

delslice(data, 1, 3)
del data_copy[1:3]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 4, 5])
for start in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
for stop in [*range(-6, 7), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]:
data = [1, 2, 3, 4, 5]
data_copy = [1, 2, 3, 4, 5]
delslice(data, start, stop)
del data_copy[start:stop]
self.assertEqual(data, data_copy)

# Custom class:
class Custom:
Expand Down
10 changes: 6 additions & 4 deletions Lib/test/test_capi/test_bytearray.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import unittest
import sys
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX

NULL = None

Expand Down Expand Up @@ -53,10 +53,12 @@ def test_fromstringandsize(self):
self.assertEqual(fromstringandsize(b'', 0), bytearray())
self.assertEqual(fromstringandsize(NULL, 0), bytearray())
self.assertEqual(len(fromstringandsize(NULL, 3)), 3)
self.assertRaises(MemoryError, fromstringandsize, NULL, sys.maxsize)
self.assertRaises(MemoryError, fromstringandsize, NULL, PY_SSIZE_T_MAX)

self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)
self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN)

def test_fromobject(self):
# Test PyByteArray_FromObject()
Expand Down Expand Up @@ -149,8 +151,8 @@ def test_resize(self):
self.assertEqual(resize(ba, 3), 0)
self.assertEqual(ba, bytearray(b'abc'))

self.assertRaises(MemoryError, resize, bytearray(), sys.maxsize)
self.assertRaises(MemoryError, resize, bytearray(1000), sys.maxsize)
self.assertRaises(MemoryError, resize, bytearray(), PY_SSIZE_T_MAX)
self.assertRaises(MemoryError, resize, bytearray(1000), PY_SSIZE_T_MAX)

# CRASHES resize(bytearray(b'abc'), -1)
# CRASHES resize(b'abc', 0)
Expand Down
10 changes: 8 additions & 2 deletions Lib/test/test_capi/test_bytes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import unittest
import sys
from test.support import import_helper

_testcapi = import_helper.import_module('_testcapi')
from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX

NULL = None

Expand Down Expand Up @@ -55,10 +55,13 @@ def test_fromstringandsize(self):
self.assertEqual(fromstringandsize(b'', 0), b'')
self.assertEqual(fromstringandsize(NULL, 0), b'')
self.assertEqual(len(fromstringandsize(NULL, 3)), 3)
self.assertRaises((MemoryError, OverflowError), fromstringandsize, NULL, sys.maxsize)
self.assertRaises((MemoryError, OverflowError),
fromstringandsize, NULL, PY_SSIZE_T_MAX)

self.assertRaises(SystemError, fromstringandsize, b'abc', -1)
self.assertRaises(SystemError, fromstringandsize, b'abc', PY_SSIZE_T_MIN)
self.assertRaises(SystemError, fromstringandsize, NULL, -1)
self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MIN)

def test_fromstring(self):
# Test PyBytes_FromString()
Expand Down Expand Up @@ -208,7 +211,10 @@ def test_decodeescape(self):
self.assertEqual(decodeescape(br'x\xa\xy', 'ignore'), b'xy')
self.assertRaises(ValueError, decodeescape, b'\\', 'spam')
self.assertEqual(decodeescape(NULL), b'')
self.assertRaises(OverflowError, decodeescape, b'abc', NULL, PY_SSIZE_T_MAX)
self.assertRaises(OverflowError, decodeescape, NULL, NULL, PY_SSIZE_T_MAX)

# CRASHES decodeescape(b'abc', NULL, -1)
# CRASHES decodeescape(NULL, NULL, 1)


Expand Down

0 comments on commit a8e1f47

Please sign in to comment.