summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2015-11-25 13:47:01 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2015-11-25 13:47:01 (GMT)
commit15095800a381a396cbc077cb5320203a8feae51a (patch)
treeba1f16c1b9be09a1f14d3af644c39e52924ee63f
parenta49de6be3669e4698ea55d22e0fdebb29be63f2e (diff)
downloadcpython-15095800a381a396cbc077cb5320203a8feae51a.zip
cpython-15095800a381a396cbc077cb5320203a8feae51a.tar.gz
cpython-15095800a381a396cbc077cb5320203a8feae51a.tar.bz2
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.
-rw-r--r--Lib/test/test_bytes.py11
-rw-r--r--Lib/test/test_float.py15
-rw-r--r--Lib/test/test_int.py7
-rw-r--r--Lib/test/test_unicode.py11
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/bytesobject.c8
-rw-r--r--Objects/floatobject.c2
-rw-r--r--Objects/longobject.c2
8 files changed, 50 insertions, 10 deletions
diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
index b00573f..0a73fcb 100644
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -744,6 +744,14 @@ class BytesTest(BaseBytesTest, unittest.TestCase):
def __index__(self):
return 42
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()
def test_from_format(self):
@@ -1465,6 +1473,9 @@ class ByteArraySubclass(bytearray):
class BytesSubclass(bytes):
pass
+class OtherBytesSubclass(bytes):
+ pass
+
class ByteArraySubclassTest(SubclassTest, unittest.TestCase):
type2test = bytearray
subclass2test = ByteArraySubclass
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index 504f39c..24fe128 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -25,6 +25,12 @@ requires_setformat = unittest.skipUnless(hasattr(float, "__setformat__"),
test_dir = os.path.dirname(__file__) or os.curdir
format_testfile = os.path.join(test_dir, 'formatfloat_testcases.txt')
+class FloatSubclass(float):
+ pass
+
+class OtherFloatSubclass(float):
+ pass
+
class GeneralFloatCases(unittest.TestCase):
def test_float(self):
@@ -167,6 +173,15 @@ class GeneralFloatCases(unittest.TestCase):
return ""
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):
self.assertFalse((1.1).is_integer())
self.assertTrue((1.).is_integer())
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
index ab3917f..4906e46 100644
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -24,6 +24,9 @@ L = [
("\u0200", ValueError)
]
+class IntSubclass(int):
+ pass
+
class IntTestCases(unittest.TestCase):
def test_basic(self):
@@ -441,6 +444,10 @@ class IntTestCases(unittest.TestCase):
good_int = TruncReturnsIntSubclass()
n = int(good_int)
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 check(s, base=None):
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index d664465..d54642f 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -42,6 +42,9 @@ def duplicate_string(text):
"""
return text.encode().decode()
+class StrSubclass(str):
+ pass
+
class UnicodeTest(string_tests.CommonTest,
string_tests.MixinStrUnicodeUserStringTest,
string_tests.MixinStrUnicodeTest,
@@ -1412,11 +1415,8 @@ class UnicodeTest(string_tests.CommonTest,
'unicode remains unicode'
)
- class UnicodeSubclass(str):
- pass
-
for text in ('ascii', '\xe9', '\u20ac', '\U0010FFFF'):
- subclass = UnicodeSubclass(text)
+ subclass = StrSubclass(text)
self.assertEqual(str(subclass), text)
self.assertEqual(len(subclass), len(text))
if text == 'ascii':
@@ -2169,6 +2169,9 @@ class UnicodeTest(string_tests.CommonTest,
s = str(StrSubclassToStrSubclass("foo"))
self.assertEqual(s, "foofoo")
self.assertIs(type(s), StrSubclassToStrSubclass)
+ s = StrSubclass(StrSubclassToStrSubclass("foo"))
+ self.assertEqual(s, "foofoo")
+ self.assertIs(type(s), StrSubclass)
def test_unicode_repr(self):
class s1:
diff --git a/Misc/NEWS b/Misc/NEWS
index 347ce48..bae6698 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@ Release date: tba
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
with a null byte.
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 5768154..27f4069 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -2445,7 +2445,7 @@ bytes_methods[] = {
};
static PyObject *
-str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static PyObject *
bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -2460,7 +2460,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
_Py_IDENTIFIER(__bytes__);
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,
&encoding, &errors))
return NULL;
@@ -2687,7 +2687,7 @@ PyBytes_FromObject(PyObject *x)
}
static PyObject *
-str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *tmp, *pnew;
Py_ssize_t n;
@@ -2696,7 +2696,7 @@ str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
tmp = bytes_new(&PyBytes_Type, args, kwds);
if (tmp == NULL)
return NULL;
- assert(PyBytes_CheckExact(tmp));
+ assert(PyBytes_Check(tmp));
n = PyBytes_GET_SIZE(tmp);
pnew = type->tp_alloc(type, n);
if (pnew != NULL) {
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 9c1b714..acd88d6 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1567,7 +1567,7 @@ float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
tmp = float_new(&PyFloat_Type, args, kwds);
if (tmp == NULL)
return NULL;
- assert(PyFloat_CheckExact(tmp));
+ assert(PyFloat_Check(tmp));
newobj = type->tp_alloc(type, 0);
if (newobj == NULL) {
Py_DECREF(tmp);
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 7036c0e..3a64b53 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -4405,7 +4405,7 @@ long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
if (tmp == NULL)
return NULL;
- assert(PyLong_CheckExact(tmp));
+ assert(PyLong_Check(tmp));
n = Py_SIZE(tmp);
if (n < 0)
n = -n;