diff options
-rw-r--r-- | Include/pyport.h | 35 | ||||
-rw-r--r-- | Modules/cmathmodule.c | 3 | ||||
-rw-r--r-- | Objects/floatobject.c | 4 |
3 files changed, 38 insertions, 4 deletions
diff --git a/Include/pyport.h b/Include/pyport.h index a831b26..b311bd8 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -287,6 +287,41 @@ extern "C" { errno = ERANGE; \ } while(0) +/* Py_ADJUST_ERANGE1(x) + * Py_ADJUST_ERANGE2(x, y) + * Set errno to 0 before calling a libm function, and invoke one of these + * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful + * for functions returning complex results). This makes two kinds of + * adjustments to errno: (A) If it looks like the platform libm set + * errno=ERANGE due to underflow, clear errno. (B) If it looks like the + * platform libm overflowed but didn't set errno, force errno to ERANGE. In + * effect, we're trying to force a useful implementation of C89 errno + * behavior. + * Caution: + * This isn't reliable. See Py_OVERFLOWED comments. + * X and Y may be evaluated more than once. + */ +#define Py_ADJUST_ERANGE1(X) \ + do { \ + if (errno == 0) { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ + errno = ERANGE; \ + } \ + else if (errno == ERANGE && (X) == 0.0) \ + errno = 0; \ + } while(0) + +#define Py_ADJUST_ERANGE2(X, Y) \ + do { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \ + (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \ + if (errno == 0) \ + errno = ERANGE; \ + } \ + else if (errno == ERANGE) \ + errno = 0; \ + } while(0) + /************************************************************************** Prototypes that are missing from the standard include files on some systems (and possibly only some versions of such systems.) diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index adf76b8..6e79680 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -337,8 +337,7 @@ math_1(PyObject *args, Py_complex (*func)(Py_complex)) PyFPE_START_PROTECT("complex function", return 0) x = (*func)(x); PyFPE_END_PROTECT(x) - Py_SET_ERANGE_IF_OVERFLOW(x.real); - Py_SET_ERANGE_IF_OVERFLOW(x.imag); + Py_ADJUST_ERANGE2(x.real, x.imag); if (errno != 0) return math_error(); else diff --git a/Objects/floatobject.c b/Objects/floatobject.c index ec8f719..83987ba 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -577,9 +577,9 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) PyFPE_START_PROTECT("pow", return NULL) ix = pow(iv, iw); PyFPE_END_PROTECT(ix) - Py_SET_ERANGE_IF_OVERFLOW(ix); + Py_ADJUST_ERANGE1(ix); if (errno != 0) { - /* XXX could it be another type of error? */ + assert(errno == ERANGE); PyErr_SetFromErrno(PyExc_OverflowError); return NULL; } |