]> granicus.if.org Git - python/commitdiff
Changes for Lee Busby's SIGFPE patch set.
authorGuido van Rossum <guido@python.org>
Fri, 14 Feb 1997 22:59:58 +0000 (22:59 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 14 Feb 1997 22:59:58 +0000 (22:59 +0000)
Two new modules fpectl and fpetest.
Surround various and sundry f.p. operations with PyFPE_*_PROTECT macros.

Modules/_tkinter.c
Modules/cmathmodule.c
Modules/fpectlmodule.c [new file with mode: 0644]
Modules/fpetestmodule.c [new file with mode: 0644]
Modules/imgfile.c
Modules/mathmodule.c
Modules/mpzmodule.c
Modules/stropmodule.c

index ba95310bcc60eb249d7dcb6dc8c7ee7f10d7fe83..33d5392dffd461c73c9e1b08fa992fa41e75b3a2 100644 (file)
@@ -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);
 }
index 7e9de1fd5b490250bb1f7b0595d612e17dc1d930..438f010c578f02a1c164374f4277e0b651ef94aa 100644 (file)
@@ -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 (file)
index 0000000..3fc5d06
--- /dev/null
@@ -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 (file)
index 0000000..2156afb
--- /dev/null
@@ -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");
+}
index 33266b9e1fd13f04614062fda6c837e546f9f494..779169d4bae6f8dcdb10d5012b9de7797c1a6ca3 100644 (file)
@@ -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;
 
index abf1d5b2dbb119cffe32ac0f1bc27b0599554d5b..bb4f1e80bd1f27cf365745573dd72491c61597c3 100644 (file)
@@ -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();
index 1f356e1a256dd38c28f07410b904fa048bfaa1f2..bf83109480ad94b58df8f86fe0441aaea408a2ec 100644 (file)
@@ -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);
index cb062ad011cc8393d3675828edfd05c77b374d37..8ddf37d2fcb3907b6887e1c372a9b31052b67d23 100644 (file)
@@ -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') {