mirror of https://github.com/python/cpython
Issue #24731: Fixed crash on converting objects with special methods
__bytes__, __trunc__, and __float__ returning instances of subclasses of bytes, int, and float to subclasses of bytes, int, and float correspondingly.
This commit is contained in:
parent
a49de6be36
commit
15095800a3
|
@ -744,6 +744,14 @@ class BytesTest(BaseBytesTest, unittest.TestCase):
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
return 42
|
return 42
|
||||||
self.assertEqual(bytes(A()), b'a')
|
self.assertEqual(bytes(A()), b'a')
|
||||||
|
# Issue #24731
|
||||||
|
class A:
|
||||||
|
def __bytes__(self):
|
||||||
|
return OtherBytesSubclass(b'abc')
|
||||||
|
self.assertEqual(bytes(A()), b'abc')
|
||||||
|
self.assertIs(type(bytes(A())), OtherBytesSubclass)
|
||||||
|
self.assertEqual(BytesSubclass(A()), b'abc')
|
||||||
|
self.assertIs(type(BytesSubclass(A())), BytesSubclass)
|
||||||
|
|
||||||
# Test PyBytes_FromFormat()
|
# Test PyBytes_FromFormat()
|
||||||
def test_from_format(self):
|
def test_from_format(self):
|
||||||
|
@ -1465,6 +1473,9 @@ class ByteArraySubclass(bytearray):
|
||||||
class BytesSubclass(bytes):
|
class BytesSubclass(bytes):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class OtherBytesSubclass(bytes):
|
||||||
|
pass
|
||||||
|
|
||||||
class ByteArraySubclassTest(SubclassTest, unittest.TestCase):
|
class ByteArraySubclassTest(SubclassTest, unittest.TestCase):
|
||||||
type2test = bytearray
|
type2test = bytearray
|
||||||
subclass2test = ByteArraySubclass
|
subclass2test = ByteArraySubclass
|
||||||
|
|
|
@ -25,6 +25,12 @@ requires_setformat = unittest.skipUnless(hasattr(float, "__setformat__"),
|
||||||
test_dir = os.path.dirname(__file__) or os.curdir
|
test_dir = os.path.dirname(__file__) or os.curdir
|
||||||
format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
|
format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
|
||||||
|
|
||||||
|
class FloatSubclass(float):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class OtherFloatSubclass(float):
|
||||||
|
pass
|
||||||
|
|
||||||
class GeneralFloatCases(unittest.TestCase):
|
class GeneralFloatCases(unittest.TestCase):
|
||||||
|
|
||||||
def test_float(self):
|
def test_float(self):
|
||||||
|
@ -167,6 +173,15 @@ class GeneralFloatCases(unittest.TestCase):
|
||||||
return ""
|
return ""
|
||||||
self.assertRaises(TypeError, time.sleep, Foo5())
|
self.assertRaises(TypeError, time.sleep, Foo5())
|
||||||
|
|
||||||
|
# Issue #24731
|
||||||
|
class F:
|
||||||
|
def __float__(self):
|
||||||
|
return OtherFloatSubclass(42.)
|
||||||
|
self.assertAlmostEqual(float(F()), 42.)
|
||||||
|
self.assertIs(type(float(F())), OtherFloatSubclass)
|
||||||
|
self.assertAlmostEqual(FloatSubclass(F()), 42.)
|
||||||
|
self.assertIs(type(FloatSubclass(F())), FloatSubclass)
|
||||||
|
|
||||||
def test_is_integer(self):
|
def test_is_integer(self):
|
||||||
self.assertFalse((1.1).is_integer())
|
self.assertFalse((1.1).is_integer())
|
||||||
self.assertTrue((1.).is_integer())
|
self.assertTrue((1.).is_integer())
|
||||||
|
|
|
@ -24,6 +24,9 @@ L = [
|
||||||
("\u0200", ValueError)
|
("\u0200", ValueError)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class IntSubclass(int):
|
||||||
|
pass
|
||||||
|
|
||||||
class IntTestCases(unittest.TestCase):
|
class IntTestCases(unittest.TestCase):
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
|
@ -441,6 +444,10 @@ class IntTestCases(unittest.TestCase):
|
||||||
good_int = TruncReturnsIntSubclass()
|
good_int = TruncReturnsIntSubclass()
|
||||||
n = int(good_int)
|
n = int(good_int)
|
||||||
self.assertEqual(n, 1)
|
self.assertEqual(n, 1)
|
||||||
|
self.assertIs(type(n), bool)
|
||||||
|
n = IntSubclass(good_int)
|
||||||
|
self.assertEqual(n, 1)
|
||||||
|
self.assertIs(type(n), IntSubclass)
|
||||||
|
|
||||||
def test_error_message(self):
|
def test_error_message(self):
|
||||||
def check(s, base=None):
|
def check(s, base=None):
|
||||||
|
|
|
@ -42,6 +42,9 @@ def duplicate_string(text):
|
||||||
"""
|
"""
|
||||||
return text.encode().decode()
|
return text.encode().decode()
|
||||||
|
|
||||||
|
class StrSubclass(str):
|
||||||
|
pass
|
||||||
|
|
||||||
class UnicodeTest(string_tests.CommonTest,
|
class UnicodeTest(string_tests.CommonTest,
|
||||||
string_tests.MixinStrUnicodeUserStringTest,
|
string_tests.MixinStrUnicodeUserStringTest,
|
||||||
string_tests.MixinStrUnicodeTest,
|
string_tests.MixinStrUnicodeTest,
|
||||||
|
@ -1412,11 +1415,8 @@ class UnicodeTest(string_tests.CommonTest,
|
||||||
'unicode remains unicode'
|
'unicode remains unicode'
|
||||||
)
|
)
|
||||||
|
|
||||||
class UnicodeSubclass(str):
|
|
||||||
pass
|
|
||||||
|
|
||||||
for text in ('ascii', '\xe9', '\u20ac', '\U0010FFFF'):
|
for text in ('ascii', '\xe9', '\u20ac', '\U0010FFFF'):
|
||||||
subclass = UnicodeSubclass(text)
|
subclass = StrSubclass(text)
|
||||||
self.assertEqual(str(subclass), text)
|
self.assertEqual(str(subclass), text)
|
||||||
self.assertEqual(len(subclass), len(text))
|
self.assertEqual(len(subclass), len(text))
|
||||||
if text == 'ascii':
|
if text == 'ascii':
|
||||||
|
@ -2169,6 +2169,9 @@ class UnicodeTest(string_tests.CommonTest,
|
||||||
s = str(StrSubclassToStrSubclass("foo"))
|
s = str(StrSubclassToStrSubclass("foo"))
|
||||||
self.assertEqual(s, "foofoo")
|
self.assertEqual(s, "foofoo")
|
||||||
self.assertIs(type(s), StrSubclassToStrSubclass)
|
self.assertIs(type(s), StrSubclassToStrSubclass)
|
||||||
|
s = StrSubclass(StrSubclassToStrSubclass("foo"))
|
||||||
|
self.assertEqual(s, "foofoo")
|
||||||
|
self.assertIs(type(s), StrSubclass)
|
||||||
|
|
||||||
def test_unicode_repr(self):
|
def test_unicode_repr(self):
|
||||||
class s1:
|
class s1:
|
||||||
|
|
|
@ -10,6 +10,10 @@ Release date: tba
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #24731: Fixed crash on converting objects with special methods
|
||||||
|
__bytes__, __trunc__, and __float__ returning instances of subclasses of
|
||||||
|
bytes, int, and float to subclasses of bytes, int, and float correspondingly.
|
||||||
|
|
||||||
- Issue #25388: Fixed tokenizer crash when processing undecodable source code
|
- Issue #25388: Fixed tokenizer crash when processing undecodable source code
|
||||||
with a null byte.
|
with a null byte.
|
||||||
|
|
||||||
|
|
|
@ -2445,7 +2445,7 @@ bytes_methods[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
@ -2460,7 +2460,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
_Py_IDENTIFIER(__bytes__);
|
_Py_IDENTIFIER(__bytes__);
|
||||||
|
|
||||||
if (type != &PyBytes_Type)
|
if (type != &PyBytes_Type)
|
||||||
return str_subtype_new(type, args, kwds);
|
return bytes_subtype_new(type, args, kwds);
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytes", kwlist, &x,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytes", kwlist, &x,
|
||||||
&encoding, &errors))
|
&encoding, &errors))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2687,7 +2687,7 @@ PyBytes_FromObject(PyObject *x)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
PyObject *tmp, *pnew;
|
PyObject *tmp, *pnew;
|
||||||
Py_ssize_t n;
|
Py_ssize_t n;
|
||||||
|
@ -2696,7 +2696,7 @@ str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
tmp = bytes_new(&PyBytes_Type, args, kwds);
|
tmp = bytes_new(&PyBytes_Type, args, kwds);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
assert(PyBytes_CheckExact(tmp));
|
assert(PyBytes_Check(tmp));
|
||||||
n = PyBytes_GET_SIZE(tmp);
|
n = PyBytes_GET_SIZE(tmp);
|
||||||
pnew = type->tp_alloc(type, n);
|
pnew = type->tp_alloc(type, n);
|
||||||
if (pnew != NULL) {
|
if (pnew != NULL) {
|
||||||
|
|
|
@ -1567,7 +1567,7 @@ float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
tmp = float_new(&PyFloat_Type, args, kwds);
|
tmp = float_new(&PyFloat_Type, args, kwds);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
assert(PyFloat_CheckExact(tmp));
|
assert(PyFloat_Check(tmp));
|
||||||
newobj = type->tp_alloc(type, 0);
|
newobj = type->tp_alloc(type, 0);
|
||||||
if (newobj == NULL) {
|
if (newobj == NULL) {
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
|
|
|
@ -4405,7 +4405,7 @@ long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
|
tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
assert(PyLong_CheckExact(tmp));
|
assert(PyLong_Check(tmp));
|
||||||
n = Py_SIZE(tmp);
|
n = Py_SIZE(tmp);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
n = -n;
|
n = -n;
|
||||||
|
|
Loading…
Reference in New Issue