diff -r c61d2c43d22e Lib/_pydecimal.py --- a/Lib/_pydecimal.py Sun May 08 14:02:35 2016 +0000 +++ b/Lib/_pydecimal.py Sun May 08 18:42:58 2016 +0300 @@ -743,7 +743,7 @@ class Decimal(object): sign = 0 else: sign = 1 - n, d = abs(f).as_integer_ratio() + n, d = abs(float(f)).as_integer_ratio() k = d.bit_length() - 1 result = _dec_from_triple(sign, str(n*5**k), -k) if cls is Decimal: diff -r c61d2c43d22e Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py Sun May 08 14:02:35 2016 +0000 +++ b/Lib/test/test_decimal.py Sun May 08 18:42:58 2016 +0300 @@ -2548,6 +2548,16 @@ class PythonAPItests(unittest.TestCase): x = random.expovariate(0.01) * (random.random() * 2.0 - 1.0) self.assertEqual(x, float(MyDecimal.from_float(x))) # roundtrip + # Issue #26974: Crash when as_integer_ratio() returns insane value. + class BadFloat(float): + def as_integer_ratio(self): + raise AssertionError + self.assertEqual(Decimal.from_float(BadFloat(1.25)), Decimal('1.25')) + class BadFloat(float): + def __abs__(self): + raise AssertionError + self.assertEqual(Decimal.from_float(BadFloat(1.25)), Decimal('1.25')) + def test_create_decimal_from_float(self): Decimal = self.decimal.Decimal Context = self.decimal.Context diff -r c61d2c43d22e Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c Sun May 08 14:02:35 2016 +0000 +++ b/Modules/_decimal/_decimal.c Sun May 08 18:42:58 2016 +0300 @@ -2213,7 +2213,7 @@ static PyObject * PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, PyObject *context) { - PyObject *dec, *tmp; + PyObject *dec, *tmp = NULL; PyObject *n, *d, *n_d; mpd_ssize_t k; double x; @@ -2256,18 +2256,22 @@ PyDecType_FromFloatExact(PyTypeObject *t return dec; } - /* absolute value of the float */ - tmp = PyObject_CallMethod(v, "__abs__", NULL); - if (tmp == NULL) { - return NULL; + /* absolute value of the float as exact float */ + if (!PyFloat_CheckExact(v) || x < 0) { + tmp = v = PyFloat_FromDouble(x < 0 ? -x : x); + if (tmp == NULL) { + return NULL; + } } /* float as integer ratio: numerator/denominator */ - n_d = PyObject_CallMethod(tmp, "as_integer_ratio", NULL); - Py_DECREF(tmp); + n_d = PyObject_CallMethod(v, "as_integer_ratio", NULL); + Py_XDECREF(tmp); if (n_d == NULL) { return NULL; } + assert(PyTuple_Check(n_d)); + assert(PyTuple_GET_SIZE(n_d) == 2); n = PyTuple_GET_ITEM(n_d, 0); d = PyTuple_GET_ITEM(n_d, 1);