changeset: 99346:37158c067b25 branch: 2.7 parent: 99341:9a4db1ac5e10 user: Serhiy Storchaka date: Wed Nov 25 15:55:54 2015 +0200 files: Lib/test/test_float.py Lib/test/test_int.py Lib/test/test_long.py Lib/test/test_str.py Lib/test/test_unicode.py Misc/NEWS Objects/floatobject.c Objects/longobject.c Objects/stringobject.c description: Issue #24731: Fixed crash on converting objects with special methods __str__, __trunc__, and __float__ returning instances of subclasses of str, long, and float to subclasses of str, long, and float correspondingly. diff -r 9a4db1ac5e10 -r 37158c067b25 Lib/test/test_float.py --- a/Lib/test/test_float.py Wed Nov 25 15:07:49 2015 +0200 +++ b/Lib/test/test_float.py Wed Nov 25 15:55:54 2015 +0200 @@ -27,6 +27,12 @@ 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): @@ -200,6 +206,15 @@ 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 -r 9a4db1ac5e10 -r 37158c067b25 Lib/test/test_int.py --- a/Lib/test/test_int.py Wed Nov 25 15:07:49 2015 +0200 +++ b/Lib/test/test_int.py Wed Nov 25 15:55:54 2015 +0200 @@ -45,6 +45,9 @@ (unichr(0x200), ValueError), ] +class IntSubclass(int): + pass + class IntLongCommonTests(object): """Mixin of test cases to share between both test_int and test_long.""" @@ -477,6 +480,18 @@ self.fail("Failed to raise TypeError with %s" % ((base, trunc_result_base),)) + class TruncReturnsIntSubclass(base): + def __trunc__(self): + return True + 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_main(): run_unittest(IntTestCases) diff -r 9a4db1ac5e10 -r 37158c067b25 Lib/test/test_long.py --- a/Lib/test/test_long.py Wed Nov 25 15:07:49 2015 +0200 +++ b/Lib/test/test_long.py Wed Nov 25 15:55:54 2015 +0200 @@ -79,6 +79,12 @@ (unichr(0x200), ValueError), ] +class LongSubclass(long): + pass + +class OtherLongSubclass(long): + pass + class LongTest(test_int.IntLongCommonTests, unittest.TestCase): ntype = long @@ -539,6 +545,17 @@ self.fail("Failed to raise TypeError with %s" % ((base, trunc_result_base),)) + class TruncReturnsLongSubclass(base): + def __long__(self): + return OtherLongSubclass(42L) + good_int = TruncReturnsLongSubclass() + n = long(good_int) + self.assertEqual(n, 42L) + self.assertIs(type(n), OtherLongSubclass) + n = LongSubclass(good_int) + self.assertEqual(n, 42L) + self.assertIs(type(n), LongSubclass) + def test_misc(self): # check the extremes in int<->long conversion diff -r 9a4db1ac5e10 -r 37158c067b25 Lib/test/test_str.py --- a/Lib/test/test_str.py Wed Nov 25 15:07:49 2015 +0200 +++ b/Lib/test/test_str.py Wed Nov 25 15:55:54 2015 +0200 @@ -4,6 +4,9 @@ from test import test_support, string_tests +class StrSubclass(str): + pass + class StrTest( string_tests.CommonTest, string_tests.MixinStrUnicodeUserStringTest, @@ -107,6 +110,9 @@ self.assertEqual(str(Foo6("bar")), "foos") self.assertEqual(str(Foo7("bar")), "foos") self.assertEqual(str(Foo8("foo")), "foofoo") + self.assertIs(type(str(Foo8("foo"))), Foo8) + self.assertEqual(StrSubclass(Foo8("foo")), "foofoo") + self.assertIs(type(StrSubclass(Foo8("foo"))), StrSubclass) self.assertEqual(str(Foo9("foo")), "string") self.assertEqual(unicode(Foo9("foo")), u"not unicode") diff -r 9a4db1ac5e10 -r 37158c067b25 Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py Wed Nov 25 15:07:49 2015 +0200 +++ b/Lib/test/test_unicode.py Wed Nov 25 15:55:54 2015 +0200 @@ -33,6 +33,9 @@ return None codecs.register(search_function) +class UnicodeSubclass(unicode): + pass + class UnicodeTest( string_tests.CommonTest, string_tests.MixinStrUnicodeUserStringTest, @@ -685,9 +688,6 @@ u'unicode remains unicode' ) - class UnicodeSubclass(unicode): - pass - self.assertEqual( unicode(UnicodeSubclass('unicode subclass becomes unicode')), u'unicode subclass becomes unicode' @@ -1269,6 +1269,9 @@ self.assertEqual(unicode(Foo6("bar")), u"foou") self.assertEqual(unicode(Foo7("bar")), u"foou") self.assertEqual(unicode(Foo8("foo")), u"foofoo") + self.assertIs(type(unicode(Foo8("foo"))), Foo8) + self.assertEqual(UnicodeSubclass(Foo8("foo")), u"foofoo") + self.assertIs(type(UnicodeSubclass(Foo8("foo"))), UnicodeSubclass) self.assertEqual(str(Foo9("foo")), "string") self.assertEqual(unicode(Foo9("foo")), u"not unicode") diff -r 9a4db1ac5e10 -r 37158c067b25 Misc/NEWS --- a/Misc/NEWS Wed Nov 25 15:07:49 2015 +0200 +++ b/Misc/NEWS Wed Nov 25 15:55:54 2015 +0200 @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #24731: Fixed crash on converting objects with special methods + __str__, __trunc__, and __float__ returning instances of subclasses of + str, long, and float to subclasses of str, long, and float correspondingly. + Library ------- diff -r 9a4db1ac5e10 -r 37158c067b25 Objects/floatobject.c --- a/Objects/floatobject.c Wed Nov 25 15:07:49 2015 +0200 +++ b/Objects/floatobject.c Wed Nov 25 15:55:54 2015 +0200 @@ -1839,7 +1839,7 @@ 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 -r 9a4db1ac5e10 -r 37158c067b25 Objects/longobject.c --- a/Objects/longobject.c Wed Nov 25 15:07:49 2015 +0200 +++ b/Objects/longobject.c Wed Nov 25 15:55:54 2015 +0200 @@ -4068,7 +4068,7 @@ 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; diff -r 9a4db1ac5e10 -r 37158c067b25 Objects/stringobject.c --- a/Objects/stringobject.c Wed Nov 25 15:07:49 2015 +0200 +++ b/Objects/stringobject.c Wed Nov 25 15:55:54 2015 +0200 @@ -3719,7 +3719,7 @@ tmp = string_new(&PyString_Type, args, kwds); if (tmp == NULL) return NULL; - assert(PyString_CheckExact(tmp)); + assert(PyString_Check(tmp)); n = PyString_GET_SIZE(tmp); pnew = type->tp_alloc(type, n); if (pnew != NULL) {