From 20ad6e86e0eaf0dfff89eb02c3fd7a9cb6cd5943 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 2 Nov 2023 09:14:02 +0200 Subject: [PATCH 1/2] gh-111495: Test C API functions with extreme sizes and indices --- Lib/test/test_capi/test_abstract.py | 54 +++++++++----- Lib/test/test_capi/test_bytearray.py | 10 +-- Lib/test/test_capi/test_bytes.py | 10 ++- Lib/test/test_capi/test_unicode.py | 101 +++++++++++++++++++++++---- 4 files changed, 135 insertions(+), 40 deletions(-) diff --git a/Lib/test/test_capi/test_abstract.py b/Lib/test/test_capi/test_abstract.py index 687ce1e6376814..5b5dfb3cc21198 100644 --- a/Lib/test/test_capi/test_abstract.py +++ b/Lib/test/test_capi/test_abstract.py @@ -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 @@ -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) @@ -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) @@ -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) @@ -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') @@ -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) @@ -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: @@ -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: diff --git a/Lib/test/test_capi/test_bytearray.py b/Lib/test/test_capi/test_bytearray.py index 6a0f313a62e0d6..833122c4e319d8 100644 --- a/Lib/test/test_capi/test_bytearray.py +++ b/Lib/test/test_capi/test_bytearray.py @@ -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 @@ -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() @@ -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) diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py index e366578ee47358..bb5d724ff187d4 100644 --- a/Lib/test/test_capi/test_bytes.py +++ b/Lib/test/test_capi/test_bytes.py @@ -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 @@ -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() @@ -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) diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 63e51eb3ba3fe4..530579fb1d25e7 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -5,6 +5,7 @@ try: import _testcapi + from _testcapi import PY_SSIZE_T_MIN, PY_SSIZE_T_MAX except ImportError: _testcapi = None try: @@ -30,9 +31,17 @@ def test_new(self): for maxchar in 0, 0x61, 0xa1, 0x4f60, 0x1f600, 0x10ffff: self.assertEqual(new(0, maxchar), '') self.assertEqual(new(5, maxchar), chr(maxchar)*5) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX, maxchar) self.assertEqual(new(0, 0x110000), '') + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2, 0x4f60) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2+1, 0x4f60) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2, 0x1f600) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//2+1, 0x1f600) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//4, 0x1f600) + self.assertRaises(MemoryError, new, PY_SSIZE_T_MAX//4+1, 0x1f600) self.assertRaises(SystemError, new, 5, 0x110000) self.assertRaises(SystemError, new, -1, 0) + self.assertRaises(SystemError, new, PY_SSIZE_T_MIN, 0) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -53,8 +62,8 @@ def test_fill(self): for to in strings[:idx]: self.assertRaises(ValueError, fill, to, 0, 0, fill_char) for to in strings[idx:]: - for start in range(7): - for length in range(-1, 7 - start): + for start in [*range(7), PY_SSIZE_T_MAX]: + for length in [*range(-1, 7 - start), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX]: filled = max(min(length, 5 - start), 0) if filled == 5 and to != strings[idx]: # narrow -> wide @@ -66,6 +75,7 @@ def test_fill(self): s = strings[0] self.assertRaises(IndexError, fill, s, -1, 0, 0x78) + self.assertRaises(IndexError, fill, s, PY_SSIZE_T_MIN, 0, 0x78) self.assertRaises(ValueError, fill, s, 0, 0, 0x110000) self.assertRaises(SystemError, fill, b'abc', 0, 0, 0x78) self.assertRaises(SystemError, fill, [], 0, 0, 0x78) @@ -76,7 +86,7 @@ def test_fill(self): @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_writechar(self): - """Test PyUnicode_ReadChar()""" + """Test PyUnicode_WriteChar()""" from _testcapi import unicode_writechar as writechar strings = [ @@ -96,10 +106,12 @@ def test_writechar(self): self.assertRaises(IndexError, writechar, 'abc', 3, 0x78) self.assertRaises(IndexError, writechar, 'abc', -1, 0x78) + self.assertRaises(IndexError, writechar, 'abc', PY_SSIZE_T_MAX, 0x78) + self.assertRaises(IndexError, writechar, 'abc', PY_SSIZE_T_MIN, 0x78) self.assertRaises(TypeError, writechar, b'abc', 0, 0x78) self.assertRaises(TypeError, writechar, [], 0, 0x78) # CRASHES writechar(NULL, 0, 0x78) - # TODO: Test PyUnicode_CopyCharacters() with non-modifiable and legacy + # TODO: Test PyUnicode_WriteChar() with non-modifiable and legacy # unicode. @support.cpython_only @@ -117,7 +129,11 @@ def test_resize(self): self.assertEqual(resize(s, 3), (s, 0)) self.assertEqual(resize(s, 2), (s[:2], 0)) self.assertEqual(resize(s, 4), (s + '\0', 0)) + self.assertEqual(resize(s, 10), (s + '\0'*7, 0)) self.assertEqual(resize(s, 0), ('', 0)) + self.assertRaises(MemoryError, resize, s, PY_SSIZE_T_MAX) + self.assertRaises(SystemError, resize, s, -1) + self.assertRaises(SystemError, resize, s, PY_SSIZE_T_MIN) self.assertRaises(SystemError, resize, b'abc', 0) self.assertRaises(SystemError, resize, [], 0) self.assertRaises(SystemError, resize, NULL, 0) @@ -196,10 +212,13 @@ def test_fromstringandsize(self): self.assertEqual(fromstringandsize(b'', 0), '') self.assertEqual(fromstringandsize(NULL, 0), '') + self.assertRaises(MemoryError, fromstringandsize, b'abc', 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) self.assertRaises(SystemError, fromstringandsize, NULL, 3) - self.assertRaises(SystemError, fromstringandsize, NULL, sys.maxsize) + self.assertRaises(SystemError, fromstringandsize, NULL, PY_SSIZE_T_MAX) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -247,7 +266,10 @@ def test_fromkindanddata(self): for kind in -1, 0, 3, 5, 8: self.assertRaises(SystemError, fromkindanddata, kind, b'') self.assertRaises(ValueError, fromkindanddata, 1, b'abc', -1) + self.assertRaises(MemoryError, fromkindanddata, 1, b'abc', PY_SSIZE_T_MAX) + self.assertRaises(ValueError, fromkindanddata, 1, b'abc', PY_SSIZE_T_MIN) self.assertRaises(ValueError, fromkindanddata, 1, NULL, -1) + self.assertRaises(ValueError, fromkindanddata, 1, NULL, PY_SSIZE_T_MIN) # CRASHES fromkindanddata(1, NULL, 1) # CRASHES fromkindanddata(4, b'\xff\xff\xff\xff') @@ -263,12 +285,14 @@ def test_substring(self): 'ab\xa1\xa2\u4f60\u597d\U0001f600\U0001f601' ] for s in strings: - for start in range(0, len(s) + 2): - for end in range(max(start-1, 0), len(s) + 2): + for start in [*range(0, len(s) + 2), PY_SSIZE_T_MAX]: + for end in [*range(max(start-1, 0), len(s) + 2), PY_SSIZE_T_MAX]: self.assertEqual(substring(s, start, end), s[start:end]) self.assertRaises(IndexError, substring, 'abc', -1, 0) + self.assertRaises(IndexError, substring, 'abc', PY_SSIZE_T_MIN, 0) self.assertRaises(IndexError, substring, 'abc', 0, -1) + self.assertRaises(IndexError, substring, 'abc', 0, PY_SSIZE_T_MIN) # CRASHES substring(b'abc', 0, 0) # CRASHES substring([], 0, 0) # CRASHES substring(NULL, 0, 0) @@ -298,7 +322,9 @@ def test_readchar(self): for i, c in enumerate(s): self.assertEqual(readchar(s, i), ord(c)) self.assertRaises(IndexError, readchar, s, len(s)) + self.assertRaises(IndexError, readchar, s, PY_SSIZE_T_MAX) self.assertRaises(IndexError, readchar, s, -1) + self.assertRaises(IndexError, readchar, s, PY_SSIZE_T_MIN) self.assertRaises(TypeError, readchar, b'abc', 0) self.assertRaises(TypeError, readchar, [], 0) @@ -733,10 +759,15 @@ def test_fromwidechar(self): if SIZEOF_WCHAR_T == 2: self.assertEqual(fromwidechar('a\U0001f600'.encode(encoding), 2), 'a\ud83d') + self.assertRaises(MemoryError, fromwidechar, b'', PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, -2) + self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, PY_SSIZE_T_MIN) self.assertEqual(fromwidechar(NULL, 0), '') self.assertRaises(SystemError, fromwidechar, NULL, 1) + self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MAX) self.assertRaises(SystemError, fromwidechar, NULL, -1) + self.assertRaises(SystemError, fromwidechar, NULL, -2) + self.assertRaises(SystemError, fromwidechar, NULL, PY_SSIZE_T_MIN) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -974,6 +1005,11 @@ def test_split(self): self.assertEqual(split('a|b|c|d', '|'), ['a', 'b', 'c', 'd']) self.assertEqual(split('a|b|c|d', '|', 2), ['a', 'b', 'c|d']) + self.assertEqual(split('a|b|c|d', '|', PY_SSIZE_T_MAX), + ['a', 'b', 'c', 'd']) + self.assertEqual(split('a|b|c|d', '|', -1), ['a', 'b', 'c', 'd']) + self.assertEqual(split('a|b|c|d', '|', PY_SSIZE_T_MIN), + ['a', 'b', 'c', 'd']) self.assertEqual(split('a|b|c|d', '\u20ac'), ['a|b|c|d']) self.assertEqual(split('a||b|c||d', '||'), ['a', 'b|c', 'd']) self.assertEqual(split('а|б|в|г', '|'), ['а', 'б', 'в', 'г']) @@ -997,6 +1033,11 @@ def test_rsplit(self): self.assertEqual(rsplit('a|b|c|d', '|'), ['a', 'b', 'c', 'd']) self.assertEqual(rsplit('a|b|c|d', '|', 2), ['a|b', 'c', 'd']) + self.assertEqual(rsplit('a|b|c|d', '|', PY_SSIZE_T_MAX), + ['a', 'b', 'c', 'd']) + self.assertEqual(rsplit('a|b|c|d', '|', -1), ['a', 'b', 'c', 'd']) + self.assertEqual(rsplit('a|b|c|d', '|', PY_SSIZE_T_MIN), + ['a', 'b', 'c', 'd']) self.assertEqual(rsplit('a|b|c|d', '\u20ac'), ['a|b|c|d']) self.assertEqual(rsplit('a||b|c||d', '||'), ['a', 'b|c', 'd']) self.assertEqual(rsplit('а|б|в|г', '|'), ['а', 'б', 'в', 'г']) @@ -1129,11 +1170,14 @@ def test_count(self): self.assertEqual(unicode_count(str, '', 0, len(str)), len(str)+1) # start < end self.assertEqual(unicode_count(str, '!', 1, len(str)+1), 1) + self.assertEqual(unicode_count(str, '!', 1, PY_SSIZE_T_MAX), 1) # start >= end self.assertEqual(unicode_count(str, '!', 0, 0), 0) self.assertEqual(unicode_count(str, '!', len(str), 0), 0) # negative self.assertEqual(unicode_count(str, '!', -len(str), -1), 1) + self.assertEqual(unicode_count(str, '!', -len(str)-1, -1), 1) + self.assertEqual(unicode_count(str, '!', PY_SSIZE_T_MIN, -1), 1) # bad arguments self.assertRaises(TypeError, unicode_count, str, b'!', 0, len(str)) self.assertRaises(TypeError, unicode_count, b"!>_= end self.assertEqual(find(str, '!', 0, 0, 1), -1) + self.assertEqual(find(str, '!', 0, 0, -1), -1) self.assertEqual(find(str, '!', len(str), 0, 1), -1) + self.assertEqual(find(str, '!', len(str), 0, -1), -1) # negative self.assertEqual(find(str, '!', -len(str), -1, 1), 0) self.assertEqual(find(str, '!', -len(str), -1, -1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, -1, 1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, -1, -1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, 1), 0) + self.assertEqual(find(str, '!', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1), 4) # bad arguments self.assertRaises(TypeError, find, str, b'!', 0, len(str), 1) self.assertRaises(TypeError, find, b"!>_= end self.assertEqual(unicode_findchar(str, ord('!'), 0, 0, 1), -1) + self.assertEqual(unicode_findchar(str, ord('!'), 0, 0, -1), -1) self.assertEqual(unicode_findchar(str, ord('!'), len(str), 0, 1), -1) + self.assertEqual(unicode_findchar(str, ord('!'), len(str), 0, -1), -1) # negative self.assertEqual(unicode_findchar(str, ord('!'), -len(str), -1, 1), 0) self.assertEqual(unicode_findchar(str, ord('!'), -len(str), -1, -1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, -1, 1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, -1, -1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, 1), 0) + self.assertEqual(unicode_findchar(str, ord('!'), PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, -1), 4) # bad arguments # CRASHES unicode_findchar(b"!>_ Date: Sat, 4 Nov 2023 10:38:35 +0200 Subject: [PATCH 2/2] Remove test with heap-buffer-overflow. --- Lib/test/test_capi/test_unicode.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 530579fb1d25e7..d8537244b39555 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -266,7 +266,6 @@ def test_fromkindanddata(self): for kind in -1, 0, 3, 5, 8: self.assertRaises(SystemError, fromkindanddata, kind, b'') self.assertRaises(ValueError, fromkindanddata, 1, b'abc', -1) - self.assertRaises(MemoryError, fromkindanddata, 1, b'abc', PY_SSIZE_T_MAX) self.assertRaises(ValueError, fromkindanddata, 1, b'abc', PY_SSIZE_T_MIN) self.assertRaises(ValueError, fromkindanddata, 1, NULL, -1) self.assertRaises(ValueError, fromkindanddata, 1, NULL, PY_SSIZE_T_MIN)