Skip to content

Commit a89b8c1

Browse files
author
Tim van der Molen
committed
Improve detection of errors from math functions
Checking errno is not always sufficient; check for floating-point exceptions, too.
1 parent 5dab287 commit a89b8c1

File tree

5 files changed

+107
-32
lines changed

5 files changed

+107
-32
lines changed

lib.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -828,21 +828,6 @@ void bclass(int c)
828828
}
829829
}
830830

831-
double errcheck(double x, const char *s)
832-
{
833-
834-
if (errno == EDOM) {
835-
errno = 0;
836-
WARNING("%s argument out of domain", s);
837-
x = 1;
838-
} else if (errno == ERANGE) {
839-
errno = 0;
840-
WARNING("%s result out of range", s);
841-
x = 1;
842-
}
843-
return x;
844-
}
845-
846831
int isclvar(const char *s) /* is s of form var=something ? */
847832
{
848833
const char *os = s;

makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ CC = $(HOSTCC) # change this is cross-compiling.
4040
# YACC = yacc -d -b awkgram
4141
YACC = bison -d
4242

43-
OFILES = b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o
43+
OFILES = b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o math.o
4444

4545
SOURCE = awk.h awkgram.tab.c awkgram.tab.h proto.h awkgram.y lex.c b.c main.c \
4646
maketab.c parse.c lib.c run.c tran.c proctab.c

math.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/****************************************************************
2+
Copyright (C) Lucent Technologies 1997
3+
All Rights Reserved
4+
5+
Permission to use, copy, modify, and distribute this software and
6+
its documentation for any purpose and without fee is hereby
7+
granted, provided that the above copyright notice appear in all
8+
copies and that both that the copyright notice and this
9+
permission notice and warranty disclaimer appear in supporting
10+
documentation, and that the name Lucent Technologies or any of
11+
its entities not be used in advertising or publicity pertaining
12+
to distribution of the software without specific, written prior
13+
permission.
14+
15+
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16+
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17+
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18+
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20+
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21+
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22+
THIS SOFTWARE.
23+
****************************************************************/
24+
25+
#pragma STDC FENV_ACCESS ON
26+
27+
#include <errno.h>
28+
#include <fenv.h>
29+
#include <math.h>
30+
#include <stdio.h>
31+
32+
#include "awk.h"
33+
34+
#ifndef FE_DIVBYZERO
35+
#define FE_DIVBYZERO 0
36+
#endif
37+
38+
#ifndef FE_INVALID
39+
#define FE_INVALID 0
40+
#endif
41+
42+
#ifndef FE_OVERFLOW
43+
#define FE_OVERFLOW 0
44+
#endif
45+
46+
#ifndef FE_UNDERFLOW
47+
#define FE_UNDERFLOW 0
48+
#endif
49+
50+
#define errclear() \
51+
do { \
52+
errno = 0; \
53+
feclearexcept(FE_ALL_EXCEPT); \
54+
} while (0)
55+
56+
static double errcheck(double x, const char *s)
57+
{
58+
if (errno == EDOM || fetestexcept(FE_INVALID)) {
59+
errno = 0;
60+
WARNING("%s argument out of domain", s);
61+
x = 1;
62+
} else if (errno == ERANGE || fetestexcept(FE_DIVBYZERO | FE_OVERFLOW |
63+
FE_UNDERFLOW)) {
64+
errno = 0;
65+
WARNING("%s result out of range", s);
66+
x = 1;
67+
}
68+
69+
return x;
70+
}
71+
72+
double exp_errcheck(double x)
73+
{
74+
errclear();
75+
return errcheck(exp(x), "exp");
76+
}
77+
78+
double log_errcheck(double x)
79+
{
80+
errclear();
81+
return errcheck(log(x), "log");
82+
}
83+
84+
double pow_errcheck(double x, double y)
85+
{
86+
errclear();
87+
return errcheck(pow(x, y), "pow");
88+
}
89+
90+
double sqrt_errcheck(double x)
91+
{
92+
errclear();
93+
return errcheck(sqrt(x), "sqrt");
94+
}

proto.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ extern void WARNING(const char *, ...)
140140
extern void error(void);
141141
extern void eprint(void);
142142
extern void bclass(int);
143-
extern double errcheck(double, const char *);
144143
extern int isclvar(const char *);
145144
extern bool is_valid_number(const char *s, bool trailing_stuff_ok,
146145
bool *no_trailing, double *result);
@@ -198,3 +197,8 @@ extern FILE *popen(const char *, const char *);
198197
extern int pclose(FILE *);
199198

200199
extern const char *flags2str(int flags);
200+
201+
extern double exp_errcheck(double);
202+
extern double log_errcheck(double);
203+
extern double pow_errcheck(double, double);
204+
extern double sqrt_errcheck(double);

run.c

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ THIS SOFTWARE.
2525
#define DEBUG
2626
#include <stdio.h>
2727
#include <ctype.h>
28-
#include <errno.h>
2928
#include <wctype.h>
3029
#include <fcntl.h>
3130
#include <setjmp.h>
@@ -1486,10 +1485,8 @@ Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
14861485
case POWER:
14871486
if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
14881487
i = ipow(i, (int) j);
1489-
else {
1490-
errno = 0;
1491-
i = errcheck(pow(i, j), "pow");
1492-
}
1488+
else
1489+
i = pow_errcheck(i, j);
14931490
break;
14941491
default: /* can't happen */
14951492
FATAL("illegal arithmetic operator %d", n);
@@ -1583,10 +1580,8 @@ Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
15831580
case POWEQ:
15841581
if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
15851582
xf = ipow(xf, (int) yf);
1586-
else {
1587-
errno = 0;
1588-
xf = errcheck(pow(xf, yf), "pow");
1589-
}
1583+
else
1584+
xf = pow_errcheck(xf, yf);
15901585
break;
15911586
default:
15921587
FATAL("illegal assignment operator %d", n);
@@ -2081,18 +2076,15 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis
20812076
u = u8_strlen(getsval(x));
20822077
break;
20832078
case FLOG:
2084-
errno = 0;
2085-
u = errcheck(log(getfval(x)), "log");
2079+
u = log_errcheck(getfval(x));
20862080
break;
20872081
case FINT:
20882082
modf(getfval(x), &u); break;
20892083
case FEXP:
2090-
errno = 0;
2091-
u = errcheck(exp(getfval(x)), "exp");
2084+
u = exp_errcheck(getfval(x));
20922085
break;
20932086
case FSQRT:
2094-
errno = 0;
2095-
u = errcheck(sqrt(getfval(x)), "sqrt");
2087+
u = sqrt_errcheck(getfval(x));
20962088
break;
20972089
case FSIN:
20982090
u = sin(getfval(x)); break;

0 commit comments

Comments
 (0)