diff --git a/calcApp/src/aCalcPerform.c b/calcApp/src/aCalcPerform.c index 66f5e60..b5c12b4 100644 --- a/calcApp/src/aCalcPerform.c +++ b/calcApp/src/aCalcPerform.c @@ -55,6 +55,17 @@ #define myMIN(a,b) (a)<(b)?(a):(b) #define SMALL 1.e-9 +/* Signed remainder that guards the one case C leaves undefined: INT_MIN % -1. + * On x86 the idiv used for '%' traps that quotient overflow as #DE, delivered + * as SIGFPE, killing the whole IOC. Mathematically x % -1 == 0 for every x, so + * return 0 for a -1 divisor instead of executing the trapping remainder. The + * divisor == 0 case is guarded separately at each call site. */ +static long safeModulo(long a, long b) +{ + if (b == -1) return 0; + return a % b; +} + static double local_random(); static int cond_search(const unsigned char **ppinst, int match); @@ -647,7 +658,7 @@ long aCalcPerform(double *p_dArg, int num_dArgs, double **pp_aArg, if ((int)ps1->a[i] == 0) { ps->a[i] = myMAXFLOAT; } else { - ps->a[i] = (double)((int)ps->a[i] % (int)ps1->a[i]); + ps->a[i] = (double)safeModulo((int)ps->a[i], (int)ps1->a[i]); } } break; @@ -671,7 +682,7 @@ long aCalcPerform(double *p_dArg, int num_dArgs, double **pp_aArg, if ((int)ps1->d == 0) { ps->a[i] = myMAXFLOAT; } else { - ps->a[i] = (double)((int)ps->a[i] % (int)ps1->d); + ps->a[i] = (double)safeModulo((int)ps->a[i], (int)ps1->d); } } break; @@ -698,7 +709,7 @@ long aCalcPerform(double *p_dArg, int num_dArgs, double **pp_aArg, if ((int)ps1->d == 0) { ps->d = myMAXFLOAT; } else { - ps->d = (double)((int)ps->d % (int)ps1->d); + ps->d = (double)safeModulo((int)ps->d, (int)ps1->d); } break; } diff --git a/calcApp/src/sCalcPerform.c b/calcApp/src/sCalcPerform.c index 31816ac..8b9f6ac 100644 --- a/calcApp/src/sCalcPerform.c +++ b/calcApp/src/sCalcPerform.c @@ -45,6 +45,18 @@ static int cond_search(const unsigned char **ppinst, int match); #define myMIN(a,b) (a)<(b)?(a):(b) #define SMALL 1.e-11 +/* Signed remainder that guards the one case C leaves undefined: INT_MIN % -1 + * (here also INT64_MIN % -1 on LP64). On x86 the idiv used for '%' traps that + * quotient overflow as #DE, delivered as SIGFPE, killing the whole IOC. + * Mathematically x % -1 == 0 for every x, so return 0 for a -1 divisor instead + * of executing the trapping remainder. The divisor == 0 case is guarded + * separately at each call site. */ +static long safeModulo(long a, long b) +{ + if (b == -1) return 0; + return a % b; +} + #define DEBUG 1 #define INIT_STACK 1 volatile int sCalcPerformDebug = 0; @@ -559,7 +571,7 @@ epicsShareFunc long --pd; if ((int)(pd[1]) == 0) return(-1); - *pd = (double)((int)(*pd) % (int)(pd[1])); + *pd = (double)safeModulo((int)(*pd), (int)(pd[1])); break; case REL_OR: @@ -1106,7 +1118,7 @@ epicsShareFunc long toDouble(ps); if ((long)ps1->d == 0) return(-1); - ps->d = (double)((long)ps->d % (long)ps1->d); + ps->d = (double)safeModulo((long)ps->d, (long)ps1->d); break; case REL_OR: