diff options
author | Guido van Rossum <guido@python.org> | 1997-02-14 22:59:58 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1997-02-14 22:59:58 (GMT) |
commit | 52fa3a69090ac098b01b28f397d9bd08f957e8cd (patch) | |
tree | c01e3347c776bd8f5deb93af7e90cfca37dea8eb | |
parent | 0ae748d3c409fc4b870baadd601a53c6a43ddf11 (diff) | |
download | cpython-52fa3a69090ac098b01b28f397d9bd08f957e8cd.zip cpython-52fa3a69090ac098b01b28f397d9bd08f957e8cd.tar.gz cpython-52fa3a69090ac098b01b28f397d9bd08f957e8cd.tar.bz2 |
Changes for Lee Busby's SIGFPE patch set.
Two new modules fpectl and fpetest.
Surround various and sundry f.p. operations with PyFPE_*_PROTECT macros.
-rw-r--r-- | Modules/_tkinter.c | 6 | ||||
-rw-r--r-- | Modules/cmathmodule.c | 2 | ||||
-rw-r--r-- | Modules/fpectlmodule.c | 244 | ||||
-rw-r--r-- | Modules/fpetestmodule.c | 228 | ||||
-rw-r--r-- | Modules/imgfile.c | 2 | ||||
-rw-r--r-- | Modules/mathmodule.c | 6 | ||||
-rw-r--r-- | Modules/mpzmodule.c | 3 | ||||
-rw-r--r-- | Modules/stropmodule.c | 2 |
8 files changed, 492 insertions, 1 deletions
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index ba95310..33d5392 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -724,10 +724,14 @@ Tkapp_ExprDouble (self, args) { char *s; double v; + int retval; if (!PyArg_Parse(args, "s", &s)) return NULL; - if (Tcl_ExprDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) + PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) + retval = Tcl_ExprDouble (Tkapp_Interp (self), s, &v); + PyFPE_END_PROTECT + if (retval == TCL_ERROR) return Tkinter_Error(self); return Py_BuildValue("d", v); } diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 7e9de1f..438f010 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -247,7 +247,9 @@ math_1(args, func) if (!PyArg_ParseTuple(args, "D", &x)) return NULL; errno = 0; + PyFPE_START_PROTECT("complex function", return 0) x = (*func)(x); + PyFPE_END_PROTECT CHECK(x.real); CHECK(x.imag); if (errno != 0) diff --git a/Modules/fpectlmodule.c b/Modules/fpectlmodule.c new file mode 100644 index 0000000..3fc5d06 --- /dev/null +++ b/Modules/fpectlmodule.c @@ -0,0 +1,244 @@ +/* + --------------------------------------------------------------------- + / Copyright (c) 1996. \ + | The Regents of the University of California. | + | All rights reserved. | + | | + | Permission to use, copy, modify, and distribute this software for | + | any purpose without fee is hereby granted, provided that this en- | + | tire notice is included in all copies of any software which is or | + | includes a copy or modification of this software and in all | + | copies of the supporting documentation for such software. | + | | + | This work was produced at the University of California, Lawrence | + | Livermore National Laboratory under contract no. W-7405-ENG-48 | + | between the U.S. Department of Energy and The Regents of the | + | University of California for the operation of UC LLNL. | + | | + | DISCLAIMER | + | | + | This software was prepared as an account of work sponsored by an | + | agency of the United States Government. Neither the United States | + | Government nor the University of California nor any of their em- | + | ployees, makes any warranty, express or implied, or assumes any | + | liability or responsibility for the accuracy, completeness, or | + | usefulness of any information, apparatus, product, or process | + | disclosed, or represents that its use would not infringe | + | privately-owned rights. Reference herein to any specific commer- | + | cial products, process, or service by trade name, trademark, | + | manufacturer, or otherwise, does not necessarily constitute or | + | imply its endorsement, recommendation, or favoring by the United | + | States Government or the University of California. The views and | + | opinions of authors expressed herein do not necessarily state or | + | reflect those of the United States Government or the University | + | of California, and shall not be used for advertising or product | + \ endorsement purposes. / + --------------------------------------------------------------------- +*/ + +/* + Floating point exception control module. + + This Python module provides bare-bones control over floating point + units from several hardware manufacturers. Specifically, it allows + the user to turn on the generation of SIGFPE whenever any of the + three serious IEEE 754 exceptions (Division by Zero, Overflow, + Invalid Operation) occurs. We currently ignore Underflow and + Inexact Result exceptions, although those could certainly be added + if desired. + + The module also establishes a signal handler for SIGFPE during + initialization. This builds on code found in the Python + distribution at Include/pyfpe.h and Python/pyfpe.c. If those files + are not in your Python distribution, find them in a patch at + ftp://icf.llnl.gov/pub/python/busby/patches.961108.tgz. + + This module is only useful to you if it happens to include code + specific for your hardware and software environment. If you can + contribute OS-specific code for new platforms, or corrections for + the code provided, it will be greatly appreciated. + + ** Version 1.0: September 20, 1996. Lee Busby, LLNL. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Python.h" +#include <signal.h> + +#ifndef WANT_SIGFPE_HANDLER +/* Define locally if they are not defined in Python. This gives only + * the limited control to induce a core dump in case of an exception. + */ +static jmp_buf PyFPE_jbuf; +static int PyFPE_counter = 0; +#endif + +typedef RETSIGTYPE Sigfunc(int); +static Sigfunc sigfpe_handler; +static void fpe_reset(Sigfunc *); + +static PyObject *fpe_error; +void initfpectl(void); +static PyObject *turnon_sigfpe (PyObject *self,PyObject *args); +static PyObject *turnoff_sigfpe (PyObject *self,PyObject *args); + +static PyMethodDef fpectl_methods[] = { + {"turnon_sigfpe", (PyCFunction) turnon_sigfpe, 1}, + {"turnoff_sigfpe", (PyCFunction) turnoff_sigfpe, 1}, + {0,0} +}; + +static PyObject *turnon_sigfpe(PyObject *self,PyObject *args) +{ + /* Do any architecture-specific one-time only initialization here. */ + + fpe_reset(sigfpe_handler); + Py_INCREF (Py_None); + return Py_None; +} + +static void fpe_reset(Sigfunc *handler) +{ + /* Reset the exception handling machinery, and reset the signal + * handler for SIGFPE to the given handler. + */ + +/*-- IRIX -----------------------------------------------------------------*/ +#if defined(sgi) + /* See man page on handle_sigfpes -- must link with -lfpe + * My usage doesn't follow the man page exactly. Maybe somebody + * else can explain handle_sigfpes to me.... + * cc -c -I/usr/local/python/include fpectlmodule.c + * ld -shared -o fpectlmodule.so fpectlmodule.o -lfpe + */ +#include <sigfpe.h> + typedef void user_routine (unsigned[5], int[2]); + typedef void abort_routine (unsigned long); + handle_sigfpes(_OFF, 0, + (user_routine *)0, + _TURN_OFF_HANDLER_ON_ERROR, + (abort_routine*)0); + handle_sigfpes(_ON, _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, + (user_routine *)0, + _ABORT_ON_ERROR, + (abort_routine*)0); + signal(SIGFPE, handler); + +/*-- SunOS and Solaris ----------------------------------------------------*/ +#elif defined(sun) + /* References: ieee_handler, ieee_sun, ieee_functions, and ieee_flags + man pages (SunOS or Solaris) + cc -c -I/usr/local/python/include fpectlmodule.c + ld -G -o fpectlmodule.so -L/opt/SUNWspro/lib fpectlmodule.o -lsunmath -lm + */ +#include <math.h> + char *mode="exception", *in="all", *out; + (void) nonstandard_arithmetic(); + (void) ieee_flags("clearall",mode,in,&out); + (void) ieee_handler("set","common",(sigfpe_handler_type)handler); + signal(SIGFPE, handler); + +/*-- HPUX -----------------------------------------------------------------*/ +#elif defined(__hppa) || defined(hppa) + /* References: fpsetmask man page */ + /* cc -Aa +z -c -I/usr/local/python/include fpectlmodule.c */ + /* ld -b -o fpectlmodule.sl fpectlmodule.o -lm */ +#include <math.h> + fpsetdefaults(); + signal(SIGFPE, handler); + +/*-- IBM AIX --------------------------------------------------------------*/ +#elif defined(__AIX) || defined(_AIX) + /* References: fp_trap, fp_enable man pages */ +#include <fptrap.h> + fp_trap(FP_TRAP_SYNC); + fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW); + signal(SIGFPE, handler); + +/*-- DEC ALPHA OSF --------------------------------------------------------*/ +#elif defined(__alpha) + /* References: exception_intro, ieee man pages */ + /* cc -c -I/usr/local/python/include fpectlmodule.c */ + /* ld -shared -o fpectlmodule.so fpectlmodule.o */ +#include <machine/fpu.h> + unsigned long fp_control = + IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF; + ieee_set_fp_control(fp_control); + signal(SIGFPE, handler); + +/*-- Cray Unicos ----------------------------------------------------------*/ +#elif defined(cray) + /* UNICOS delivers SIGFPE by default, but no matherr */ +#ifdef HAS_LIBMSET + libmset(-1); +#endif + signal(SIGFPE, handler); + +/*-- Linux ----------------------------------------------------------------*/ +#elif defined(linux) + /* Linux delivers SIGFPE by default, + except for log(0), atanh(-1), 0.^0. + */ + signal(SIGFPE, handler); + +/*-- NeXT -----------------------------------------------------------------*/ +#elif defined(NeXT) && defined(m68k) && defined(__GNUC__) + /* NeXT needs explicit csr set to generate SIGFPE */ + asm("fmovel #0x1400,fpcr"); /* set OVFL and ZD bits */ + signal(SIGFPE, handler); + +/*-- Microsoft Windows, NT ------------------------------------------------*/ +#elif defined(_MSC_VER) + /* Reference: Visual C++ Books Online 4.2, + Run-Time Library Reference, _control87, _controlfp */ +#include <float.h> + unsigned int cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW; + (void)_controlfp(0, cw); + signal(SIGFPE, handler); + +/*-- Give Up --------------------------------------------------------------*/ +#else + fputs("Operation not implemented\n", stderr); +#endif + +} + +static PyObject *turnoff_sigfpe(PyObject *self,PyObject *args) +{ + fputs("Operation not implemented\n", stderr); + Py_INCREF (Py_None); + return Py_None; +} + +static void sigfpe_handler(int signo) +{ + fpe_reset(sigfpe_handler); + if(PyFPE_counter) { + longjmp(PyFPE_jbuf, 1); + } else { + Py_FatalError("Unprotected floating point exception"); + } +} + +void initfpectl(void) +{ + PyObject *m, *d; + static int already_initialized = 0; + + if (already_initialized) return; + m = Py_InitModule("fpectl", fpectl_methods); + d = PyModule_GetDict(m); + fpe_error = PyString_FromString("fpectl.error"); + PyDict_SetItemString(d, "error", fpe_error); + + if (PyErr_Occurred()) + Py_FatalError("Cannot initialize module fpectl"); + already_initialized = 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/Modules/fpetestmodule.c b/Modules/fpetestmodule.c new file mode 100644 index 0000000..2156afb --- /dev/null +++ b/Modules/fpetestmodule.c @@ -0,0 +1,228 @@ +/* + --------------------------------------------------------------------- + / Copyright (c) 1996. \ + | The Regents of the University of California. | + | All rights reserved. | + | | + | Permission to use, copy, modify, and distribute this software for | + | any purpose without fee is hereby granted, provided that this en- | + | tire notice is included in all copies of any software which is or | + | includes a copy or modification of this software and in all | + | copies of the supporting documentation for such software. | + | | + | This work was produced at the University of California, Lawrence | + | Livermore National Laboratory under contract no. W-7405-ENG-48 | + | between the U.S. Department of Energy and The Regents of the | + | University of California for the operation of UC LLNL. | + | | + | DISCLAIMER | + | | + | This software was prepared as an account of work sponsored by an | + | agency of the United States Government. Neither the United States | + | Government nor the University of California nor any of their em- | + | ployees, makes any warranty, express or implied, or assumes any | + | liability or responsibility for the accuracy, completeness, or | + | usefulness of any information, apparatus, product, or process | + | disclosed, or represents that its use would not infringe | + | privately-owned rights. Reference herein to any specific commer- | + | cial products, process, or service by trade name, trademark, | + | manufacturer, or otherwise, does not necessarily constitute or | + | imply its endorsement, recommendation, or favoring by the United | + | States Government or the University of California. The views and | + | opinions of authors expressed herein do not necessarily state or | + | reflect those of the United States Government or the University | + | of California, and shall not be used for advertising or product | + \ endorsement purposes. / + --------------------------------------------------------------------- +*/ + +/* + Floating point exception test module. + + */ + +#include "Python.h" + +static PyObject *fpe_error; +void initfpetest(void); +static PyObject *test(PyObject *self,PyObject *args); +static int db0(void); +static int overflow(void); +static int nest1(double); +static int nest2(double); +static double nest3(double); + +static PyMethodDef fpetest_methods[] = { + {"test", (PyCFunction) test, 1}, + {0,0} +}; + +static PyObject *test(PyObject *self,PyObject *args) +{ + int i = 0, r; + + fprintf(stderr,"Test trapping overflow\n"); + r = overflow(); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test trapping division by zero\n"); + r = db0(); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test nested protection zones, outer zone\n"); + r = nest1(0.0); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test nested protection zones, inner zone\n"); + fprintf(stderr,"(Note: Return will apparently come from outer zone.)\n"); + r = nest1(1.0); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test nested protection zones, trailing outer zone\n"); + r = nest1(2.0); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test nested function calls, prior error\n"); + r = nest2(0.0); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test nested function calls, interior error\n"); + r = nest2(1.0); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Test nested function calls, trailing error\n"); + r = nest2(2.0); + if(r){ + fprintf(stderr,"(Note: No exception was raised.)\n"); + PyErr_Clear(); + }else{ + fprintf(stderr,"Trapped:: "); + PyErr_Print(); + PyErr_Clear(); + } + i += r; + + fprintf(stderr,"Number of tests failed: %d\n", i); + Py_INCREF (Py_None); + return Py_None; +} + +static int nest1(double x) +{ + double a = 1.0; + PyFPE_START_PROTECT("Division by zero, outer zone", return 0) + a = 1./x; + PyFPE_START_PROTECT("Division by zero, inner zone", return 0) + a = 1./(1. - x); + PyFPE_END_PROTECT + a = 1./(2. - x); + PyFPE_END_PROTECT + return(1); +} + +static int nest2(double x) +{ + double a = 1.0; + PyFPE_START_PROTECT("Division by zero, prior error", return 0) + a = 1./x; + a = nest3(x); + a = 1./(2. - x); + PyFPE_END_PROTECT + return(1); +} + +static double nest3(double x) +{ + double result; + PyFPE_START_PROTECT("Division by zero, nest3 error", return 0) + result = 1./(1. - x); + PyFPE_END_PROTECT + return result; +} + +static int db0(void) +{ + double a = 1.0; + PyFPE_START_PROTECT("Division by zero", return 0) + a = 1./(a - 1.); + PyFPE_END_PROTECT + return(1); +} + +static int overflow(void) +{ + double a, b = 1.e200; + PyFPE_START_PROTECT("Overflow", return 0) + a = b*b; + PyFPE_END_PROTECT + return(1); +} + +void initfpetest(void) +{ + PyObject *m, *d; + + m = Py_InitModule("fpetest", fpetest_methods); + d = PyModule_GetDict(m); + fpe_error = PyString_FromString("fpetest.error"); + PyDict_SetItemString(d, "error", fpe_error); + + if (PyErr_Occurred()) + Py_FatalError("Cannot initialize module fpetest"); +} diff --git a/Modules/imgfile.c b/Modules/imgfile.c index 33266b9..779169d 100644 --- a/Modules/imgfile.c +++ b/Modules/imgfile.c @@ -387,8 +387,10 @@ PyObject *args; iclose(image); return NULL; } + PyFPE_START_PROTECT("readscaled", return 0) xfac = (float)xsize/(float)xwtd; yfac = (float)ysize/(float)ywtd; + PyFPE_END_PROTECT cdatap = PyString_AsString(rv); idatap = (long *)cdatap; diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index abf1d5b..bb4f1e8 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -80,7 +80,9 @@ math_1(args, func) if (! PyArg_Parse(args, "d", &x)) return NULL; errno = 0; + PyFPE_START_PROTECT("in math_1", return 0) x = (*func)(x); + PyFPE_END_PROTECT CHECK(x); if (errno != 0) return math_error(); @@ -97,7 +99,9 @@ math_2(args, func) if (! PyArg_Parse(args, "(dd)", &x, &y)) return NULL; errno = 0; + PyFPE_START_PROTECT("in math_2", return 0) x = (*func)(x, y); + PyFPE_END_PROTECT CHECK(x); if (errno != 0) return math_error(); @@ -173,7 +177,9 @@ math_ldexp(self, args) if (! PyArg_Parse(args, "(dd)", &x, &y)) return NULL; errno = 0; + PyFPE_START_PROTECT("ldexp", return 0) x = ldexp(x, (int)y); + PyFPE_END_PROTECT CHECK(x); if (errno != 0) return math_error(); diff --git a/Modules/mpzmodule.c b/Modules/mpzmodule.c index 1f356e1..bf83109 100644 --- a/Modules/mpzmodule.c +++ b/Modules/mpzmodule.c @@ -1488,6 +1488,8 @@ mpz_float(self) /* let those bits come, let those bits go, e.g. dismantle mpzscratch, build PyFloatObject */ + /* Can this overflow? Dunno, protect against that possibility. */ + PyFPE_START_PROTECT("mpz_float", return 0) x = 0.0; mulstate = 1.0; while (i--) { @@ -1495,6 +1497,7 @@ mpz_float(self) mulstate *= multiplier; mpz_div_2exp(&mpzscratch, &mpzscratch, BITS_PER_MP_LIMB); } + PyFPE_END_PROTECT assert(mpz_cmp_ui(&mpzscratch, (unsigned long int)0) == 0); mpz_clear(&mpzscratch); diff --git a/Modules/stropmodule.c b/Modules/stropmodule.c index cb062ad..8ddf37d 100644 --- a/Modules/stropmodule.c +++ b/Modules/stropmodule.c @@ -661,7 +661,9 @@ strop_atof(self, args) return NULL; } errno = 0; + PyFPE_START_PROTECT("strop_atof", return 0) x = strtod(s, &end); + PyFPE_END_PROTECT while (*end && isspace(Py_CHARMASK(*end))) end++; if (*end != '\0') { |