Kaydet (Commit) a853a8ba authored tarafından Benjamin Peterson's avatar Benjamin Peterson Kaydeden (comit) GitHub

bpo-31373: fix undefined floating-point demotions (#3396)

üst c988ae01
...@@ -215,4 +215,16 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short); ...@@ -215,4 +215,16 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short);
(X) == -Py_HUGE_VAL)) (X) == -Py_HUGE_VAL))
#endif #endif
/* Return whether integral type *type* is signed or not. */
#define _Py_IntegralTypeSigned(type) ((type)(-1) < 0)
/* Return the maximum value of integral type *type*. */
#define _Py_IntegralTypeMax(type) ((_Py_IntegralTypeSigned(type)) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0)
/* Return the minimum value of integral type *type*. */
#define _Py_IntegralTypeMin(type) ((_Py_IntegralTypeSigned(type)) ? -_Py_IntegralTypeMax(type) - 1 : 0)
/* Check whether *v* is in the range of integral type *type*. This is most
* useful if *v* is floating-point, since demoting a floating-point *v* to an
* integral type that cannot represent *v*'s integral part is undefined
* behavior. */
#define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
#endif /* Py_PYMATH_H */ #endif /* Py_PYMATH_H */
Fix several possible instances of undefined behavior due to floating-point
demotions.
...@@ -2233,13 +2233,15 @@ _PyFloat_Pack4(double x, unsigned char *p, int le) ...@@ -2233,13 +2233,15 @@ _PyFloat_Pack4(double x, unsigned char *p, int le)
} }
else { else {
float y = (float)x;
const unsigned char *s = (unsigned char*)&y;
int i, incr = 1; int i, incr = 1;
if (Py_IS_INFINITY(y) && !Py_IS_INFINITY(x)) if (fabs(x) > FLT_MAX && !Py_IS_INFINITY(x))
goto Overflow; goto Overflow;
unsigned char s[sizeof(float)];
float y = (float)x;
memcpy(s, &y, sizeof(float));
if ((float_format == ieee_little_endian_format && !le) if ((float_format == ieee_little_endian_format && !le)
|| (float_format == ieee_big_endian_format && le)) { || (float_format == ieee_big_endian_format && le)) {
p += 3; p += 3;
...@@ -2247,7 +2249,7 @@ _PyFloat_Pack4(double x, unsigned char *p, int le) ...@@ -2247,7 +2249,7 @@ _PyFloat_Pack4(double x, unsigned char *p, int le)
} }
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
*p = *s++; *p = s[i];
p += incr; p += incr;
} }
return 0; return 0;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "Python.h" #include "Python.h"
#include <ctype.h> #include <ctype.h>
#include <float.h>
#ifdef __cplusplus #ifdef __cplusplus
...@@ -858,6 +859,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, ...@@ -858,6 +859,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
double dval = PyFloat_AsDouble(arg); double dval = PyFloat_AsDouble(arg);
if (PyErr_Occurred()) if (PyErr_Occurred())
RETURN_ERR_OCCURRED; RETURN_ERR_OCCURRED;
else if (dval > FLT_MAX)
*p = (float)INFINITY;
else if (dval < -FLT_MAX)
*p = (float)-INFINITY;
else else
*p = (float) dval; *p = (float) dval;
break; break;
......
...@@ -97,7 +97,7 @@ static int ...@@ -97,7 +97,7 @@ static int
_PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
double denominator, _PyTime_round_t round) double denominator, _PyTime_round_t round)
{ {
double intpart, err; double intpart;
/* volatile avoids optimization changing how numbers are rounded */ /* volatile avoids optimization changing how numbers are rounded */
volatile double floatpart; volatile double floatpart;
...@@ -115,14 +115,13 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator, ...@@ -115,14 +115,13 @@ _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
} }
assert(0.0 <= floatpart && floatpart < denominator); assert(0.0 <= floatpart && floatpart < denominator);
*sec = (time_t)intpart; if (!_Py_InIntegralTypeRange(time_t, intpart)) {
*numerator = (long)floatpart;
err = intpart - (double)*sec;
if (err <= -1.0 || err >= 1.0) {
error_time_t_overflow(); error_time_t_overflow();
return -1; return -1;
} }
*sec = (time_t)intpart;
*numerator = (long)floatpart;
return 0; return 0;
} }
...@@ -150,7 +149,7 @@ int ...@@ -150,7 +149,7 @@ int
_PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
{ {
if (PyFloat_Check(obj)) { if (PyFloat_Check(obj)) {
double intpart, err; double intpart;
/* volatile avoids optimization changing how numbers are rounded */ /* volatile avoids optimization changing how numbers are rounded */
volatile double d; volatile double d;
...@@ -158,12 +157,11 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) ...@@ -158,12 +157,11 @@ _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round)
d = _PyTime_Round(d, round); d = _PyTime_Round(d, round);
(void)modf(d, &intpart); (void)modf(d, &intpart);
*sec = (time_t)intpart; if (!_Py_InIntegralTypeRange(time_t, intpart)) {
err = intpart - (double)*sec;
if (err <= -1.0 || err >= 1.0) {
error_time_t_overflow(); error_time_t_overflow();
return -1; return -1;
} }
*sec = (time_t)intpart;
return 0; return 0;
} }
else { else {
...@@ -180,7 +178,9 @@ _PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec, ...@@ -180,7 +178,9 @@ _PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec,
{ {
int res; int res;
res = _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9, round); res = _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9, round);
if (res == 0) {
assert(0 <= *nsec && *nsec < SEC_TO_NS); assert(0 <= *nsec && *nsec < SEC_TO_NS);
}
return res; return res;
} }
...@@ -190,7 +190,9 @@ _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, ...@@ -190,7 +190,9 @@ _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec,
{ {
int res; int res;
res = _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); res = _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round);
if (res == 0) {
assert(0 <= *usec && *usec < SEC_TO_US); assert(0 <= *usec && *usec < SEC_TO_US);
}
return res; return res;
} }
...@@ -276,7 +278,6 @@ static int ...@@ -276,7 +278,6 @@ static int
_PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round, _PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round,
long unit_to_ns) long unit_to_ns)
{ {
double err;
/* volatile avoids optimization changing how numbers are rounded */ /* volatile avoids optimization changing how numbers are rounded */
volatile double d; volatile double d;
...@@ -285,12 +286,11 @@ _PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round, ...@@ -285,12 +286,11 @@ _PyTime_FromFloatObject(_PyTime_t *t, double value, _PyTime_round_t round,
d *= (double)unit_to_ns; d *= (double)unit_to_ns;
d = _PyTime_Round(d, round); d = _PyTime_Round(d, round);
*t = (_PyTime_t)d; if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
err = d - (double)*t;
if (fabs(err) >= 1.0) {
_PyTime_overflow(); _PyTime_overflow();
return -1; return -1;
} }
*t = (_PyTime_t)d;
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment