summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2022-10-30 06:23:20 (GMT)
committerGitHub <noreply@github.com>2022-10-30 06:23:20 (GMT)
commit76f989dc3e668d15b3ec9a90bf6530276530acac (patch)
tree627d40bcf2a29e819b5dfef1fc270c6848e09756
parent3ac8c0ab6ee819a14b1c8e0992acbaf376a46058 (diff)
downloadcpython-76f989dc3e668d15b3ec9a90bf6530276530acac.zip
cpython-76f989dc3e668d15b3ec9a90bf6530276530acac.tar.gz
cpython-76f989dc3e668d15b3ec9a90bf6530276530acac.tar.bz2
gh-98783: Fix crashes when `str` subclasses are used in `_PyUnicode_Equal` (#98806)
-rw-r--r--Include/cpython/unicodeobject.h2
-rw-r--r--Lib/test/test_descr.py19
-rw-r--r--Lib/test/test_long.py12
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst2
-rw-r--r--Objects/unicodeobject.c4
5 files changed, 36 insertions, 3 deletions
diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h
index 3ca6ace..8444507a 100644
--- a/Include/cpython/unicodeobject.h
+++ b/Include/cpython/unicodeobject.h
@@ -945,7 +945,7 @@ PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*);
and where the hash values are equal (i.e. a very probable match) */
PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *);
-/* Equality check. Returns -1 on failure. */
+/* Equality check. */
PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *, PyObject *);
PyAPI_FUNC(int) _PyUnicode_WideCharString_Converter(PyObject *, void *);
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 037c859..40cf81f 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1317,6 +1317,15 @@ order (MRO) for bases """
with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"):
X().a
+ # Test string subclass in `__slots__`, see gh-98783
+ class SubStr(str):
+ pass
+ class X(object):
+ __slots__ = (SubStr('x'),)
+ X().x = 1
+ with self.assertRaisesRegex(AttributeError, "'X' object has no attribute 'a'"):
+ X().a
+
def test_slots_special(self):
# Testing __dict__ and __weakref__ in __slots__...
class D(object):
@@ -3589,6 +3598,16 @@ order (MRO) for bases """
self.assertEqual(o.__str__(), '41')
self.assertEqual(o.__repr__(), 'A repr')
+ def test_repr_with_module_str_subclass(self):
+ # gh-98783
+ class StrSub(str):
+ pass
+ class Some:
+ pass
+ Some.__module__ = StrSub('example')
+ self.assertIsInstance(repr(Some), str) # should not crash
+ self.assertIsInstance(repr(Some()), str) # should not crash
+
def test_keyword_arguments(self):
# Testing keyword arguments to __init__, __call__...
def f(a): return a
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index b6407b5..77b37ca 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -1334,6 +1334,12 @@ class LongTest(unittest.TestCase):
b'\xff\xff\xff\xff\xff')
self.assertRaises(OverflowError, (1).to_bytes, 0, 'big')
+ # gh-98783
+ class SubStr(str):
+ pass
+ self.assertEqual((0).to_bytes(1, SubStr('big')), b'\x00')
+ self.assertEqual((0).to_bytes(0, SubStr('little')), b'')
+
def test_from_bytes(self):
def check(tests, byteorder, signed=False):
def equivalent_python(byte_array, byteorder, signed=False):
@@ -1534,6 +1540,12 @@ class LongTest(unittest.TestCase):
self.assertRaises(TypeError, int.from_bytes, MissingBytes())
self.assertRaises(ZeroDivisionError, int.from_bytes, RaisingBytes())
+ # gh-98783
+ class SubStr(str):
+ pass
+ self.assertEqual(int.from_bytes(b'', SubStr('big')), 0)
+ self.assertEqual(int.from_bytes(b'\x00', SubStr('little')), 0)
+
@support.cpython_only
def test_from_bytes_small(self):
# bpo-46361
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst
new file mode 100644
index 0000000..da1e61e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-10-28-14-52-55.gh-issue-98783.iG0kMs.rst
@@ -0,0 +1,2 @@
+Fix multiple crashes in debug mode when ``str`` subclasses
+are used instead of ``str`` itself.
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index d090915..9dd0c42 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -10444,8 +10444,8 @@ unicode_compare_eq(PyObject *str1, PyObject *str2)
int
_PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
- assert(PyUnicode_CheckExact(str1));
- assert(PyUnicode_CheckExact(str2));
+ assert(PyUnicode_Check(str1));
+ assert(PyUnicode_Check(str2));
if (str1 == str2) {
return 1;
}