summaryrefslogtreecommitdiff
path: root/Objects/floatobject.c
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2017-02-04 15:05:40 -0800
committerSteve Dower <steve.dower@microsoft.com>2017-02-04 15:05:40 -0800
commitb2fa705fd3887c326e811c418469c784353027f4 (patch)
treeb3428f73de91453edbfd4df1a5d4a212d182eb44 /Objects/floatobject.c
parent134e58fd3aaa2e91390041e143f3f0a21a60142b (diff)
parentb53654b6dbfce8318a7d4d1cdaddca7a7fec194b (diff)
downloadcpython-b2fa705fd3887c326e811c418469c784353027f4.tar.gz
Issue #29392: Prevent crash when passing invalid arguments into msvcrt module.
Diffstat (limited to 'Objects/floatobject.c')
-rw-r--r--Objects/floatobject.c352
1 files changed, 278 insertions, 74 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d92bec35b5..80bf71efd2 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -124,11 +124,43 @@ PyFloat_FromDouble(double fval)
return (PyObject *) op;
}
+static PyObject *
+float_from_string_inner(const char *s, Py_ssize_t len, void *obj)
+{
+ double x;
+ const char *end;
+ const char *last = s + len;
+ /* strip space */
+ while (s < last && Py_ISSPACE(*s)) {
+ s++;
+ }
+
+ while (s < last - 1 && Py_ISSPACE(last[-1])) {
+ last--;
+ }
+
+ /* We don't care about overflow or underflow. If the platform
+ * supports them, infinities and signed zeroes (on underflow) are
+ * fine. */
+ x = PyOS_string_to_double(s, (char **)&end, NULL);
+ if (end != last) {
+ PyErr_Format(PyExc_ValueError,
+ "could not convert string to float: "
+ "%R", obj);
+ return NULL;
+ }
+ else if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ else {
+ return PyFloat_FromDouble(x);
+ }
+}
+
PyObject *
PyFloat_FromString(PyObject *v)
{
- const char *s, *last, *end;
- double x;
+ const char *s;
PyObject *s_buffer = NULL;
Py_ssize_t len;
Py_buffer view = {NULL, NULL};
@@ -169,27 +201,8 @@ PyFloat_FromString(PyObject *v)
Py_TYPE(v)->tp_name);
return NULL;
}
- last = s + len;
- /* strip space */
- while (s < last && Py_ISSPACE(*s))
- s++;
- while (s < last - 1 && Py_ISSPACE(last[-1]))
- last--;
- /* We don't care about overflow or underflow. If the platform
- * supports them, infinities and signed zeroes (on underflow) are
- * fine. */
- x = PyOS_string_to_double(s, (char **)&end, NULL);
- if (end != last) {
- PyErr_Format(PyExc_ValueError,
- "could not convert string to float: "
- "%R", v);
- result = NULL;
- }
- else if (x == -1.0 && PyErr_Occurred())
- result = NULL;
- else
- result = PyFloat_FromDouble(x);
-
+ result = _Py_string_to_number_with_underscores(s, len, "float", v, v,
+ float_from_string_inner);
PyBuffer_Release(&view);
Py_XDECREF(s_buffer);
return result;
@@ -215,35 +228,49 @@ double
PyFloat_AsDouble(PyObject *op)
{
PyNumberMethods *nb;
- PyFloatObject *fo;
+ PyObject *res;
double val;
- if (op && PyFloat_Check(op))
- return PyFloat_AS_DOUBLE((PyFloatObject*) op);
-
if (op == NULL) {
PyErr_BadArgument();
return -1;
}
- if ((nb = Py_TYPE(op)->tp_as_number) == NULL || nb->nb_float == NULL) {
- PyErr_SetString(PyExc_TypeError, "a float is required");
- return -1;
+ if (PyFloat_Check(op)) {
+ return PyFloat_AS_DOUBLE(op);
}
- fo = (PyFloatObject*) (*nb->nb_float) (op);
- if (fo == NULL)
- return -1;
- if (!PyFloat_Check(fo)) {
- Py_DECREF(fo);
- PyErr_SetString(PyExc_TypeError,
- "nb_float should return float object");
+ nb = Py_TYPE(op)->tp_as_number;
+ if (nb == NULL || nb->nb_float == NULL) {
+ PyErr_Format(PyExc_TypeError, "must be real number, not %.50s",
+ op->ob_type->tp_name);
return -1;
}
- val = PyFloat_AS_DOUBLE(fo);
- Py_DECREF(fo);
+ res = (*nb->nb_float) (op);
+ if (res == NULL) {
+ return -1;
+ }
+ if (!PyFloat_CheckExact(res)) {
+ if (!PyFloat_Check(res)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.50s.__float__ returned non-float (type %.50s)",
+ op->ob_type->tp_name, res->ob_type->tp_name);
+ Py_DECREF(res);
+ return -1;
+ }
+ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+ "%.50s.__float__ returned non-float (type %.50s). "
+ "The ability to return an instance of a strict subclass of float "
+ "is deprecated, and may be removed in a future version of Python.",
+ op->ob_type->tp_name, res->ob_type->tp_name)) {
+ Py_DECREF(res);
+ return -1;
+ }
+ }
+ val = PyFloat_AS_DOUBLE(res);
+ Py_DECREF(res);
return val;
}
@@ -1195,7 +1222,7 @@ Return a hexadecimal representation of a floating-point number.\n\
static PyObject *
float_fromhex(PyObject *cls, PyObject *arg)
{
- PyObject *result_as_float, *result;
+ PyObject *result;
double x;
long exp, top_exp, lsb, key_digit;
char *s, *coeff_start, *s_store, *coeff_end, *exp_start, *s_end;
@@ -1247,7 +1274,7 @@ float_fromhex(PyObject *cls, PyObject *arg)
* exp+4*ndigits and exp-4*ndigits are within the range of a long.
*/
- s = _PyUnicode_AsStringAndSize(arg, &length);
+ s = PyUnicode_AsUTF8AndSize(arg, &length);
if (s == NULL)
return NULL;
s_end = s + length;
@@ -1410,11 +1437,10 @@ float_fromhex(PyObject *cls, PyObject *arg)
s++;
if (s != s_end)
goto parse_error;
- result_as_float = Py_BuildValue("(d)", negate ? -x : x);
- if (result_as_float == NULL)
- return NULL;
- result = PyObject_CallObject(cls, result_as_float);
- Py_DECREF(result_as_float);
+ result = PyFloat_FromDouble(negate ? -x : x);
+ if (cls != (PyObject *)&PyFloat_Type && result != NULL) {
+ Py_SETREF(result, PyObject_CallFunctionObjArgs(cls, result, NULL));
+ }
return result;
overflow_error:
@@ -1451,29 +1477,23 @@ float_as_integer_ratio(PyObject *v, PyObject *unused)
int exponent;
int i;
- PyObject *prev;
PyObject *py_exponent = NULL;
PyObject *numerator = NULL;
PyObject *denominator = NULL;
PyObject *result_pair = NULL;
PyNumberMethods *long_methods = PyLong_Type.tp_as_number;
-#define INPLACE_UPDATE(obj, call) \
- prev = obj; \
- obj = call; \
- Py_DECREF(prev); \
-
CONVERT_TO_DOUBLE(v, self);
if (Py_IS_INFINITY(self)) {
- PyErr_SetString(PyExc_OverflowError,
- "Cannot pass infinity to float.as_integer_ratio.");
- return NULL;
+ PyErr_SetString(PyExc_OverflowError,
+ "cannot convert Infinity to integer ratio");
+ return NULL;
}
if (Py_IS_NAN(self)) {
- PyErr_SetString(PyExc_ValueError,
- "Cannot pass NaN to float.as_integer_ratio.");
- return NULL;
+ PyErr_SetString(PyExc_ValueError,
+ "cannot convert NaN to integer ratio");
+ return NULL;
}
PyFPE_START_PROTECT("as_integer_ratio", goto error);
@@ -1489,29 +1509,31 @@ float_as_integer_ratio(PyObject *v, PyObject *unused)
to be truncated by PyLong_FromDouble(). */
numerator = PyLong_FromDouble(float_part);
- if (numerator == NULL) goto error;
+ if (numerator == NULL)
+ goto error;
+ denominator = PyLong_FromLong(1);
+ if (denominator == NULL)
+ goto error;
+ py_exponent = PyLong_FromLong(Py_ABS(exponent));
+ if (py_exponent == NULL)
+ goto error;
/* fold in 2**exponent */
- denominator = PyLong_FromLong(1);
- py_exponent = PyLong_FromLong(labs((long)exponent));
- if (py_exponent == NULL) goto error;
- INPLACE_UPDATE(py_exponent,
- long_methods->nb_lshift(denominator, py_exponent));
- if (py_exponent == NULL) goto error;
if (exponent > 0) {
- INPLACE_UPDATE(numerator,
- long_methods->nb_multiply(numerator, py_exponent));
- if (numerator == NULL) goto error;
+ Py_SETREF(numerator,
+ long_methods->nb_lshift(numerator, py_exponent));
+ if (numerator == NULL)
+ goto error;
}
else {
- Py_DECREF(denominator);
- denominator = py_exponent;
- py_exponent = NULL;
+ Py_SETREF(denominator,
+ long_methods->nb_lshift(denominator, py_exponent));
+ if (denominator == NULL)
+ goto error;
}
result_pair = PyTuple_Pack(2, numerator, denominator);
-#undef INPLACE_UPDATE
error:
Py_XDECREF(py_exponent);
Py_XDECREF(denominator);
@@ -1606,7 +1628,7 @@ float_getformat(PyTypeObject *v, PyObject* arg)
Py_TYPE(arg)->tp_name);
return NULL;
}
- s = _PyUnicode_AsString(arg);
+ s = PyUnicode_AsUTF8(arg);
if (s == NULL)
return NULL;
if (strcmp(s, "double") == 0) {
@@ -1966,8 +1988,120 @@ _PyFloat_DebugMallocStats(FILE *out)
/*----------------------------------------------------------------------------
- * _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
+ * _PyFloat_{Pack,Unpack}{2,4,8}. See floatobject.h.
+ * To match the NPY_HALF_ROUND_TIES_TO_EVEN behavior in:
+ * https://github.com/numpy/numpy/blob/master/numpy/core/src/npymath/halffloat.c
+ * We use:
+ * bits = (unsigned short)f; Note the truncation
+ * if ((f - bits > 0.5) || (f - bits == 0.5 && bits % 2)) {
+ * bits++;
+ * }
*/
+
+int
+_PyFloat_Pack2(double x, unsigned char *p, int le)
+{
+ unsigned char sign;
+ int e;
+ double f;
+ unsigned short bits;
+ int incr = 1;
+
+ if (x == 0.0) {
+ sign = (copysign(1.0, x) == -1.0);
+ e = 0;
+ bits = 0;
+ }
+ else if (Py_IS_INFINITY(x)) {
+ sign = (x < 0.0);
+ e = 0x1f;
+ bits = 0;
+ }
+ else if (Py_IS_NAN(x)) {
+ /* There are 2046 distinct half-precision NaNs (1022 signaling and
+ 1024 quiet), but there are only two quiet NaNs that don't arise by
+ quieting a signaling NaN; we get those by setting the topmost bit
+ of the fraction field and clearing all other fraction bits. We
+ choose the one with the appropriate sign. */
+ sign = (copysign(1.0, x) == -1.0);
+ e = 0x1f;
+ bits = 512;
+ }
+ else {
+ sign = (x < 0.0);
+ if (sign) {
+ x = -x;
+ }
+
+ f = frexp(x, &e);
+ if (f < 0.5 || f >= 1.0) {
+ PyErr_SetString(PyExc_SystemError,
+ "frexp() result out of range");
+ return -1;
+ }
+
+ /* Normalize f to be in the range [1.0, 2.0) */
+ f *= 2.0;
+ e--;
+
+ if (e >= 16) {
+ goto Overflow;
+ }
+ else if (e < -25) {
+ /* |x| < 2**-25. Underflow to zero. */
+ f = 0.0;
+ e = 0;
+ }
+ else if (e < -14) {
+ /* |x| < 2**-14. Gradual underflow */
+ f = ldexp(f, 14 + e);
+ e = 0;
+ }
+ else /* if (!(e == 0 && f == 0.0)) */ {
+ e += 15;
+ f -= 1.0; /* Get rid of leading 1 */
+ }
+
+ f *= 1024.0; /* 2**10 */
+ /* Round to even */
+ bits = (unsigned short)f; /* Note the truncation */
+ assert(bits < 1024);
+ assert(e < 31);
+ if ((f - bits > 0.5) || ((f - bits == 0.5) && (bits % 2 == 1))) {
+ ++bits;
+ if (bits == 1024) {
+ /* The carry propagated out of a string of 10 1 bits. */
+ bits = 0;
+ ++e;
+ if (e == 31)
+ goto Overflow;
+ }
+ }
+ }
+
+ bits |= (e << 10) | (sign << 15);
+
+ /* Write out result. */
+ if (le) {
+ p += 1;
+ incr = -1;
+ }
+
+ /* First byte */
+ *p = (unsigned char)((bits >> 8) & 0xFF);
+ p += incr;
+
+ /* Second byte */
+ *p = (unsigned char)(bits & 0xFF);
+
+ return 0;
+
+ Overflow:
+ PyErr_SetString(PyExc_OverflowError,
+ "float too large to pack with e format");
+ return -1;
+}
+
int
_PyFloat_Pack4(double x, unsigned char *p, int le)
{
@@ -2203,6 +2337,76 @@ _PyFloat_Pack8(double x, unsigned char *p, int le)
}
double
+_PyFloat_Unpack2(const unsigned char *p, int le)
+{
+ unsigned char sign;
+ int e;
+ unsigned int f;
+ double x;
+ int incr = 1;
+
+ if (le) {
+ p += 1;
+ incr = -1;
+ }
+
+ /* First byte */
+ sign = (*p >> 7) & 1;
+ e = (*p & 0x7C) >> 2;
+ f = (*p & 0x03) << 8;
+ p += incr;
+
+ /* Second byte */
+ f |= *p;
+
+ if (e == 0x1f) {
+#ifdef PY_NO_SHORT_FLOAT_REPR
+ if (f == 0) {
+ /* Infinity */
+ return sign ? -Py_HUGE_VAL : Py_HUGE_VAL;
+ }
+ else {
+ /* NaN */
+#ifdef Py_NAN
+ return sign ? -Py_NAN : Py_NAN;
+#else
+ PyErr_SetString(
+ PyExc_ValueError,
+ "can't unpack IEEE 754 NaN "
+ "on platform that does not support NaNs");
+ return -1;
+#endif /* #ifdef Py_NAN */
+ }
+#else
+ if (f == 0) {
+ /* Infinity */
+ return _Py_dg_infinity(sign);
+ }
+ else {
+ /* NaN */
+ return _Py_dg_stdnan(sign);
+ }
+#endif /* #ifdef PY_NO_SHORT_FLOAT_REPR */
+ }
+
+ x = (double)f / 1024.0;
+
+ if (e == 0) {
+ e = -14;
+ }
+ else {
+ x += 1.0;
+ e -= 15;
+ }
+ x = ldexp(x, e);
+
+ if (sign)
+ x = -x;
+
+ return x;
+}
+
+double
_PyFloat_Unpack4(const unsigned char *p, int le)
{
if (float_format == unknown_format) {