(feenv_nomask_test): Avoid dumping core in the child.
[kopensolaris-gnu/glibc.git] / math / test-fenv.c
1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de> and
4    Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 /* Tests for ISO C 9X 7.6: Floating-point environment  */
22
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE
25 #endif
26
27 #include <complex.h>
28 #include <math.h>
29 #include <float.h>
30 #include <fenv.h>
31
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/wait.h>
39 #include <sys/resource.h>
40
41 /*
42   Since not all architectures might define all exceptions, we define
43   a private set and map accordingly.
44 */
45 #define NO_EXC 0
46 #define INEXACT_EXC 0x1
47 #define DIVBYZERO_EXC 0x2
48 #define UNDERFLOW_EXC 0x04
49 #define OVERFLOW_EXC 0x08
50 #define INVALID_EXC 0x10
51 #define ALL_EXC \
52         (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \
53          INVALID_EXC)
54
55 static int count_errors;
56
57 /* Test whether a given exception was raised.  */
58 static void
59 test_single_exception (short int exception,
60                        short int exc_flag,
61                        fexcept_t fe_flag,
62                        const char *flag_name)
63 {
64   if (exception & exc_flag)
65     {
66       if (fetestexcept (fe_flag))
67         printf ("  Pass: Exception \"%s\" is set\n", flag_name);
68       else
69         {
70           printf ("  Fail: Exception \"%s\" is not set\n", flag_name);
71           ++count_errors;
72         }
73     }
74   else
75     {
76       if (fetestexcept (fe_flag))
77         {
78           printf ("  Fail: Exception \"%s\" is set\n", flag_name);
79           ++count_errors;
80         }
81       else
82         {
83           printf ("  Pass: Exception \"%s\" is not set\n", flag_name);
84         }
85     }
86 }
87
88 static void
89 test_exceptions (const char *test_name, short int exception,
90                  int ignore_inexact)
91 {
92   printf ("Test: %s\n", test_name);
93 #ifdef FE_DIVBYZERO
94   test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
95                          "DIVBYZERO");
96 #endif
97 #ifdef FE_INVALID
98   test_single_exception (exception, INVALID_EXC, FE_INVALID,
99                          "INVALID");
100 #endif
101 #ifdef FE_INEXACT
102   if (!ignore_inexact)
103     test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
104                            "INEXACT");
105 #endif
106 #ifdef FE_UNDERFLOW
107   test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
108                          "UNDERFLOW");
109 #endif
110 #ifdef FE_OVERFLOW
111   test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
112                          "OVERFLOW");
113 #endif
114 }
115
116 static void
117 print_rounding (int rounding)
118 {
119
120   switch (rounding) {
121 #ifdef FE_TONEAREST
122   case FE_TONEAREST:
123     printf ("TONEAREST");
124     break;
125 #endif
126 #ifdef FE_UPWARD
127   case FE_UPWARD:
128     printf ("UPWARD");
129     break;
130 #endif
131 #ifdef FE_DOWNWARD
132   case FE_DOWNWARD:
133     printf ("DOWNWARD");
134     break;
135 #endif
136 #ifdef FE_TOWARDZERO
137   case FE_TOWARDZERO:
138     printf ("TOWARDZERO");
139     break;
140 #endif
141   }
142   printf (".\n");
143 }
144
145
146 static void
147 test_rounding (const char *test_name, int rounding_mode)
148 {
149   int curr_rounding = fegetround ();
150
151   printf ("Test: %s\n", test_name);
152   if (curr_rounding == rounding_mode)
153     {
154       printf ("  Pass: Rounding mode is ");
155       print_rounding (curr_rounding);
156     }
157   else {
158     ++count_errors;
159     printf ("  Fail: Rounding mode is ");
160     print_rounding (curr_rounding);
161   }
162 }
163
164
165 static void
166 set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
167 {
168   char str[200];
169   /* The standard allows the inexact exception to be set together with the
170      underflow and overflow exceptions.  So ignore the inexact flag if the
171      others are raised.  */
172   int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0;
173
174   strcpy (str, test_name);
175   strcat (str, ": set flag, with rest not set");
176   feclearexcept (FE_ALL_EXCEPT);
177   feraiseexcept (exception);
178   test_exceptions (str, fe_exc, ignore_inexact);
179
180   strcpy (str, test_name);
181   strcat (str, ": clear flag, rest also unset");
182   feclearexcept (exception);
183   test_exceptions (str, NO_EXC, ignore_inexact);
184
185   strcpy (str, test_name);
186   strcat (str, ": set flag, with rest set");
187   feraiseexcept (FE_ALL_EXCEPT ^ exception);
188   feraiseexcept (exception);
189   test_exceptions (str, ALL_EXC, 0);
190
191   strcpy (str, test_name);
192   strcat (str, ": clear flag, leave rest set");
193   feclearexcept (exception);
194   test_exceptions (str, ALL_EXC ^ fe_exc, 0);
195 }
196
197 static void
198 fe_tests (void)
199 {
200   /* clear all exceptions and test if all are cleared */
201   feclearexcept (FE_ALL_EXCEPT);
202   test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
203                    NO_EXC, 0);
204
205   /* raise all exceptions and test if all are raised */
206   feraiseexcept (FE_ALL_EXCEPT);
207   test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
208                    ALL_EXC, 0);
209   feclearexcept (FE_ALL_EXCEPT);
210
211 #ifdef FE_DIVBYZERO
212   set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
213 #endif
214 #ifdef FE_INVALID
215   set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
216 #endif
217 #ifdef FE_INEXACT
218   set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
219 #endif
220 #ifdef FE_UNDERFLOW
221   set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
222 #endif
223 #ifdef FE_OVERFLOW
224   set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
225 #endif
226 }
227
228 /* Test that program aborts with no masked interrupts */
229 static void
230 feenv_nomask_test (const char *flag_name, int fe_exc)
231 {
232 #if defined FE_NOMASK_ENV
233   int status;
234   pid_t pid;
235   fenv_t saved;
236
237   fegetenv (&saved);
238   errno = 0;
239   fesetenv (FE_NOMASK_ENV);
240   status = errno;
241   fesetenv (&saved);
242   if (status == ENOSYS)
243     {
244       printf ("Test: not testing FE_NOMASK_ENV, it isn't implemented.\n");
245       return;
246     }
247
248   printf ("Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n");
249   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
250   pid = fork  ();
251   if (pid == 0)
252     {
253 #ifdef RLIMIT_CORE
254       /* Try to avoid dumping core.  */
255       struct rlimit core_limit;
256       core_limit.rlim_cur = 0;
257       core_limit.rlim_max = 0;
258       setrlimit (RLIMIT_CORE, &core_limit);
259 #endif
260
261       fesetenv (FE_NOMASK_ENV);
262       feraiseexcept (fe_exc);
263       exit (2);
264     }
265   else if (pid < 0)
266     {
267       if (errno != ENOSYS)
268         {
269           printf ("  Fail: Could not fork.\n");
270           ++count_errors;
271         }
272       else
273         printf ("  `fork' not implemented, test ignored.\n");
274     }
275   else {
276     if (waitpid (pid, &status, 0) != pid)
277       {
278         printf ("  Fail: waitpid call failed.\n");
279         ++count_errors;
280       }
281     else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
282       printf ("  Pass: Process received SIGFPE.\n");
283     else
284       {
285         printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
286                 status);
287         ++count_errors;
288       }
289   }
290 #endif
291 }
292
293 /* Test that program doesn't abort with default environment */
294 static void
295 feenv_mask_test (const char *flag_name, int fe_exc)
296 {
297   int status;
298   pid_t pid;
299
300   printf ("Test: after fesetenv (FE_DFL_ENV) processes will not abort\n");
301   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
302   pid = fork ();
303   if (pid == 0)
304     {
305 #ifdef RLIMIT_CORE
306       /* Try to avoid dumping core.  */
307       struct rlimit core_limit;
308       core_limit.rlim_cur = 0;
309       core_limit.rlim_max = 0;
310       setrlimit (RLIMIT_CORE, &core_limit);
311 #endif
312
313       fesetenv (FE_DFL_ENV);
314       feraiseexcept (fe_exc);
315       exit (2);
316     }
317   else if (pid < 0)
318     {
319       if (errno != ENOSYS)
320         {
321           printf ("  Fail: Could not fork.\n");
322           ++count_errors;
323         }
324       else
325         printf ("  `fork' not implemented, test ignored.\n");
326     }
327   else {
328     if (waitpid (pid, &status, 0) != pid)
329       {
330         printf ("  Fail: waitpid call failed.\n");
331         ++count_errors;
332       }
333     else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
334       printf ("  Pass: Process exited normally.\n");
335     else
336       {
337         printf ("  Fail: Process exited abnormally with status %d.\n",
338                 status);
339         ++count_errors;
340       }
341   }
342 }
343
344
345
346 static void
347 feenv_tests (void)
348 {
349
350 #ifdef FE_DIVBYZERO
351   feenv_nomask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
352   feenv_mask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
353 #endif
354 #ifdef FE_INVALID
355   feenv_nomask_test ("FE_INVALID", FE_INVALID);
356   feenv_mask_test ("FE_INVALID", FE_INVALID);
357 #endif
358 #ifdef FE_INEXACT
359   feenv_nomask_test ("FE_INEXACT", FE_INEXACT);
360   feenv_mask_test ("FE_INEXACT", FE_INEXACT);
361 #endif
362 #ifdef FE_UNDERFLOW
363   feenv_nomask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
364   feenv_mask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
365 #endif
366 #ifdef FE_OVERFLOW
367   feenv_nomask_test ("FE_OVERFLOW", FE_OVERFLOW);
368   feenv_mask_test ("FE_OVERFLOW", FE_OVERFLOW);
369 #endif
370   fesetenv (FE_DFL_ENV);
371 }
372
373
374 /* IEC 559 and ISO C 9X define a default startup environment */
375 static void
376 initial_tests (void)
377 {
378   test_exceptions ("Initially all exceptions should be cleared",
379                    NO_EXC, 0);
380   test_rounding ("Rounding direction should be initalized to nearest",
381                  FE_TONEAREST);
382 }
383
384 int
385 main (void)
386 {
387   initial_tests ();
388   fe_tests ();
389   feenv_tests ();
390
391   if (count_errors)
392     {
393       printf ("\n%d errors occured.\n", count_errors);
394       exit (1);
395     }
396   printf ("\n All tests passed successfully.\n");
397   exit (0);
398 }