summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/pyport.h35
-rw-r--r--Modules/cmathmodule.c3
-rw-r--r--Objects/floatobject.c4
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;
}