Skip to content

Commit 5efe2ee

Browse files
sweeneydesobolevn
andauthored
[3.11] gh-98783: Fix crashes when str subclasses are used in _PyUnicode_Equal (GH-98806) (#98871)
* gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (GH-98806) (cherry picked from commit 76f989d) Co-authored-by: Nikita Sobolev <[email protected]>
1 parent a55bd6f commit 5efe2ee

File tree

4 files changed

+35
-2
lines changed

4 files changed

+35
-2
lines changed

Lib/test/test_descr.py

+19
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,15 @@ class X(object):
13101310
with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"):
13111311
X().a
13121312

1313+
# Test string subclass in `__slots__`, see gh-98783
1314+
class SubStr(str):
1315+
pass
1316+
class X(object):
1317+
__slots__ = (SubStr('x'),)
1318+
X().x = 1
1319+
with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"):
1320+
X().a
1321+
13131322
def test_slots_special(self):
13141323
# Testing __dict__ and __weakref__ in __slots__...
13151324
class D(object):
@@ -3581,6 +3590,16 @@ def __repr__(self):
35813590
self.assertEqual(o.__str__(), '41')
35823591
self.assertEqual(o.__repr__(), 'A repr')
35833592

3593+
def test_repr_with_module_str_subclass(self):
3594+
# gh-98783
3595+
class StrSub(str):
3596+
pass
3597+
class Some:
3598+
pass
3599+
Some.__module__ = StrSub('example')
3600+
self.assertIsInstance(repr(Some), str) # should not crash
3601+
self.assertIsInstance(repr(Some()), str) # should not crash
3602+
35843603
def test_keyword_arguments(self):
35853604
# Testing keyword arguments to __init__, __call__...
35863605
def f(a): return a

Lib/test/test_long.py

+12
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,12 @@ def equivalent_python(n, length, byteorder, signed=False):
13341334
b'\xff\xff\xff\xff\xff')
13351335
self.assertRaises(OverflowError, (1).to_bytes, 0, 'big')
13361336

1337+
# gh-98783
1338+
class SubStr(str):
1339+
pass
1340+
self.assertEqual((0).to_bytes(1, SubStr('big')), b'\x00')
1341+
self.assertEqual((0).to_bytes(0, SubStr('little')), b'')
1342+
13371343
def test_from_bytes(self):
13381344
def check(tests, byteorder, signed=False):
13391345
def equivalent_python(byte_array, byteorder, signed=False):
@@ -1534,6 +1540,12 @@ def __bytes__(self):
15341540
self.assertRaises(TypeError, int.from_bytes, MissingBytes())
15351541
self.assertRaises(ZeroDivisionError, int.from_bytes, RaisingBytes())
15361542

1543+
# gh-98783
1544+
class SubStr(str):
1545+
pass
1546+
self.assertEqual(int.from_bytes(b'', SubStr('big')), 0)
1547+
self.assertEqual(int.from_bytes(b'\x00', SubStr('little')), 0)
1548+
15371549
@support.cpython_only
15381550
def test_from_bytes_small(self):
15391551
# bpo-46361
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix multiple crashes in debug mode when ``str`` subclasses
2+
are used instead of ``str`` itself.

Objects/unicodeobject.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -11134,8 +11134,8 @@ unicode_compare_eq(PyObject *str1, PyObject *str2)
1113411134
int
1113511135
_PyUnicode_Equal(PyObject *str1, PyObject *str2)
1113611136
{
11137-
assert(PyUnicode_CheckExact(str1));
11138-
assert(PyUnicode_CheckExact(str2));
11137+
assert(PyUnicode_Check(str1));
11138+
assert(PyUnicode_Check(str2));
1113911139
if (str1 == str2) {
1114011140
return 1;
1114111141
}

0 commit comments

Comments
 (0)