From cb61e5d9b59c1a5f18dd34edebb054d1e19f1581 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 26 Sep 2010 10:37:12 +0000 Subject: [PATCH] Issue #9869: Make long() and PyNumber_Long return something of type long for a class whose __long__ method returns a plain int. This fixes an interpreter crash (due to long_subtype_new assuming PyNumber_Long returns a long) when initializing an instance of a long subclass from an object whose __long__ method returns a plain int. --- Lib/test/test_class.py | 2 +- Lib/test/test_long.py | 16 ++++++++++++++++ Misc/NEWS | 5 +++++ Objects/abstract.c | 9 ++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 914ea73c40d..e7b775250ae 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -513,7 +513,7 @@ class ClassTests(unittest.TestCase): callLst[:] = [] as_long = long(mixIntAndLong) - self.assertEquals(type(as_long), int) + self.assertEquals(type(as_long), long) self.assertEquals(as_long, 64) self.assertCallStack([('__long__', (mixIntAndLong,))]) diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index 412ec7c5251..9706a8e0c93 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -601,6 +601,22 @@ class LongTest(unittest.TestCase): slicemin, slicemax = X()[-2L**100:2L**100] self.assertEqual(X()[slicemin:slicemax], (slicemin, slicemax)) + def test_issue9869(self): + # Issue 9869: Interpreter crash when initializing an instance + # of a long subclass from an object whose __long__ method returns + # a plain int. + class BadLong(object): + def __long__(self): + return 1000000 + + class MyLong(long): + pass + + x = MyLong(BadLong()) + self.assertIsInstance(x, long) + self.assertEqual(x, 1000000) + + # ----------------------------------- tests of auto int->long conversion def test_auto_overflow(self): diff --git a/Misc/NEWS b/Misc/NEWS index 90a17617fa7..99d905df2c5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,11 @@ What's New in Python 2.7.1? Core and Builtins ----------------- +- Issue #9869: Make long() and PyNumber_Long return something of type + long for a class whose __long__ method returns a plain int. This + fixes an interpreter crash when initializing an instance of a long + subclass from an object whose __long__ method returns a plain int. + - Issue #9797: pystate.c wrongly assumed that zero couldn't be a valid thread-local storage key. diff --git a/Objects/abstract.c b/Objects/abstract.c index 75de1aa047a..1e79ddf4a35 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1713,7 +1713,14 @@ PyNumber_Long(PyObject *o) if (m && m->nb_long) { /* This should include subclasses of long */ /* Classic classes always take this branch. */ PyObject *res = m->nb_long(o); - if (res && (!PyInt_Check(res) && !PyLong_Check(res))) { + if (res == NULL) + return NULL; + if (PyInt_Check(res)) { + long value = PyInt_AS_LONG(res); + Py_DECREF(res); + return PyLong_FromLong(value); + } + else if (!PyLong_Check(res)) { PyErr_Format(PyExc_TypeError, "__long__ returned non-long (type %.200s)", res->ob_type->tp_name);