Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dc5a508

Browse files
committed
SF bug 525705: [2.2] underflow raise OverflowException.
Another year in the quest to out-guess random C behavior. Added macros Py_ADJUST_ERANGE1(X) and Py_ADJUST_ERANGE2(X, Y). The latter is useful for functions with complex results. Two corrections to errno- after-libm-call are attempted: 1. If the platform set errno to ERANGE due to underflow, clear errno. Some unknown subset of libm versions and link options do this. It's allowed by C89, but I never figured anyone would do it. 2. If the platform did not set errno but overflow occurred, force errno to ERANGE. C89 required setting errno to ERANGE, but C99 doesn't. Some unknown subset of libm versions and link options do it the C99 way now. Bugfix candidate, but hold off until some Linux people actually try it, with and without -lieee. I'll send a help plea to Python-Dev.
1 parent d50e544 commit dc5a508

3 files changed

Lines changed: 38 additions & 4 deletions

File tree

Include/pyport.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,41 @@ extern "C" {
287287
errno = ERANGE; \
288288
} while(0)
289289

290+
/* Py_ADJUST_ERANGE1(x)
291+
* Py_ADJUST_ERANGE2(x, y)
292+
* Set errno to 0 before calling a libm function, and invoke one of these
293+
* macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful
294+
* for functions returning complex results). This makes two kinds of
295+
* adjustments to errno: (A) If it looks like the platform libm set
296+
* errno=ERANGE due to underflow, clear errno. (B) If it looks like the
297+
* platform libm overflowed but didn't set errno, force errno to ERANGE. In
298+
* effect, we're trying to force a useful implementation of C89 errno
299+
* behavior.
300+
* Caution:
301+
* This isn't reliable. See Py_OVERFLOWED comments.
302+
* X and Y may be evaluated more than once.
303+
*/
304+
#define Py_ADJUST_ERANGE1(X) \
305+
do { \
306+
if (errno == 0) { \
307+
if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \
308+
errno = ERANGE; \
309+
} \
310+
else if (errno == ERANGE && (X) == 0.0) \
311+
errno = 0; \
312+
} while(0)
313+
314+
#define Py_ADJUST_ERANGE2(X, Y) \
315+
do { \
316+
if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \
317+
(Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \
318+
if (errno == 0) \
319+
errno = ERANGE; \
320+
} \
321+
else if (errno == ERANGE) \
322+
errno = 0; \
323+
} while(0)
324+
290325
/**************************************************************************
291326
Prototypes that are missing from the standard include files on some systems
292327
(and possibly only some versions of such systems.)

Modules/cmathmodule.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,7 @@ math_1(PyObject *args, Py_complex (*func)(Py_complex))
337337
PyFPE_START_PROTECT("complex function", return 0)
338338
x = (*func)(x);
339339
PyFPE_END_PROTECT(x)
340-
Py_SET_ERANGE_IF_OVERFLOW(x.real);
341-
Py_SET_ERANGE_IF_OVERFLOW(x.imag);
340+
Py_ADJUST_ERANGE2(x.real, x.imag);
342341
if (errno != 0)
343342
return math_error();
344343
else

Objects/floatobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,9 +577,9 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
577577
PyFPE_START_PROTECT("pow", return NULL)
578578
ix = pow(iv, iw);
579579
PyFPE_END_PROTECT(ix)
580-
Py_SET_ERANGE_IF_OVERFLOW(ix);
580+
Py_ADJUST_ERANGE1(ix);
581581
if (errno != 0) {
582-
/* XXX could it be another type of error? */
582+
assert(errno == ERANGE);
583583
PyErr_SetFromErrno(PyExc_OverflowError);
584584
return NULL;
585585
}

0 commit comments

Comments
 (0)