1 | /* Copyright (C) 1997-2024 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* Tests for ISO C99 7.6: Floating-point environment */ |
19 | |
20 | #ifndef _GNU_SOURCE |
21 | # define _GNU_SOURCE |
22 | #endif |
23 | |
24 | #include <complex.h> |
25 | #include <math.h> |
26 | #include <float.h> |
27 | #include <fenv.h> |
28 | |
29 | #include <errno.h> |
30 | #include <signal.h> |
31 | #include <stdlib.h> |
32 | #include <stdio.h> |
33 | #include <string.h> |
34 | #include <unistd.h> |
35 | #include <sys/wait.h> |
36 | #include <sys/resource.h> |
37 | #include <math-tests.h> |
38 | |
39 | /* |
40 | Since not all architectures might define all exceptions, we define |
41 | a private set and map accordingly. |
42 | */ |
43 | #define NO_EXC 0 |
44 | #define INEXACT_EXC 0x1 |
45 | #define DIVBYZERO_EXC 0x2 |
46 | #define UNDERFLOW_EXC 0x04 |
47 | #define OVERFLOW_EXC 0x08 |
48 | #define INVALID_EXC 0x10 |
49 | #define ALL_EXC \ |
50 | (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC \ |
51 | | INVALID_EXC) |
52 | |
53 | static int count_errors; |
54 | |
55 | #if FE_ALL_EXCEPT |
56 | /* Test whether a given exception was raised. */ |
57 | static void |
58 | test_single_exception (short int exception, |
59 | short int exc_flag, |
60 | fexcept_t fe_flag, |
61 | const char *flag_name) |
62 | { |
63 | if (exception & exc_flag) |
64 | { |
65 | if (fetestexcept (excepts: fe_flag)) |
66 | printf (format: " Pass: Exception \"%s\" is set\n" , flag_name); |
67 | else |
68 | { |
69 | printf (format: " Fail: Exception \"%s\" is not set\n" , flag_name); |
70 | ++count_errors; |
71 | } |
72 | } |
73 | else |
74 | { |
75 | if (fetestexcept (excepts: fe_flag)) |
76 | { |
77 | printf (format: " Fail: Exception \"%s\" is set\n" , flag_name); |
78 | ++count_errors; |
79 | } |
80 | else |
81 | { |
82 | printf (format: " Pass: Exception \"%s\" is not set\n" , flag_name); |
83 | } |
84 | } |
85 | } |
86 | #endif |
87 | |
88 | static void |
89 | test_exceptions (const char *test_name, short int exception, |
90 | int ignore_inexact) |
91 | { |
92 | printf (format: "Test: %s\n" , test_name); |
93 | #ifdef FE_DIVBYZERO |
94 | test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO, |
95 | flag_name: "DIVBYZERO" ); |
96 | #endif |
97 | #ifdef FE_INVALID |
98 | test_single_exception (exception, INVALID_EXC, FE_INVALID, |
99 | flag_name: "INVALID" ); |
100 | #endif |
101 | #ifdef FE_INEXACT |
102 | if (!ignore_inexact) |
103 | test_single_exception (exception, INEXACT_EXC, FE_INEXACT, |
104 | flag_name: "INEXACT" ); |
105 | #endif |
106 | #ifdef FE_UNDERFLOW |
107 | test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW, |
108 | flag_name: "UNDERFLOW" ); |
109 | #endif |
110 | #ifdef FE_OVERFLOW |
111 | test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW, |
112 | flag_name: "OVERFLOW" ); |
113 | #endif |
114 | } |
115 | |
116 | static void |
117 | print_rounding (int rounding) |
118 | { |
119 | |
120 | switch (rounding) |
121 | { |
122 | #ifdef FE_TONEAREST |
123 | case FE_TONEAREST: |
124 | printf (format: "TONEAREST" ); |
125 | break; |
126 | #endif |
127 | #ifdef FE_UPWARD |
128 | case FE_UPWARD: |
129 | printf (format: "UPWARD" ); |
130 | break; |
131 | #endif |
132 | #ifdef FE_DOWNWARD |
133 | case FE_DOWNWARD: |
134 | printf (format: "DOWNWARD" ); |
135 | break; |
136 | #endif |
137 | #ifdef FE_TOWARDZERO |
138 | case FE_TOWARDZERO: |
139 | printf (format: "TOWARDZERO" ); |
140 | break; |
141 | #endif |
142 | } |
143 | printf (format: ".\n" ); |
144 | } |
145 | |
146 | |
147 | static void |
148 | test_rounding (const char *test_name, int rounding_mode) |
149 | { |
150 | int curr_rounding = fegetround (); |
151 | |
152 | printf (format: "Test: %s\n" , test_name); |
153 | if (curr_rounding == rounding_mode) |
154 | { |
155 | printf (format: " Pass: Rounding mode is " ); |
156 | print_rounding (rounding: curr_rounding); |
157 | } |
158 | else |
159 | { |
160 | ++count_errors; |
161 | printf (format: " Fail: Rounding mode is " ); |
162 | print_rounding (rounding: curr_rounding); |
163 | } |
164 | } |
165 | |
166 | |
167 | #if FE_ALL_EXCEPT |
168 | static void |
169 | set_single_exc (const char *test_name, int fe_exc, fexcept_t exception) |
170 | { |
171 | char str[200]; |
172 | /* The standard allows the inexact exception to be set together with the |
173 | underflow and overflow exceptions. So ignore the inexact flag if the |
174 | others are raised. */ |
175 | int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0; |
176 | |
177 | strcpy (dest: str, src: test_name); |
178 | strcat (dest: str, src: ": set flag, with rest not set" ); |
179 | feclearexcept (FE_ALL_EXCEPT); |
180 | feraiseexcept (excepts: exception); |
181 | test_exceptions (test_name: str, exception: fe_exc, ignore_inexact); |
182 | |
183 | strcpy (dest: str, src: test_name); |
184 | strcat (dest: str, src: ": clear flag, rest also unset" ); |
185 | feclearexcept (excepts: exception); |
186 | test_exceptions (test_name: str, NO_EXC, ignore_inexact); |
187 | |
188 | strcpy (dest: str, src: test_name); |
189 | strcat (dest: str, src: ": set flag, with rest set" ); |
190 | feraiseexcept (FE_ALL_EXCEPT ^ exception); |
191 | feraiseexcept (excepts: exception); |
192 | test_exceptions (test_name: str, ALL_EXC, ignore_inexact: 0); |
193 | |
194 | strcpy (dest: str, src: test_name); |
195 | strcat (dest: str, src: ": clear flag, leave rest set" ); |
196 | feclearexcept (excepts: exception); |
197 | test_exceptions (test_name: str, ALL_EXC ^ fe_exc, ignore_inexact: 0); |
198 | } |
199 | |
200 | static void |
201 | update_single_exc (const char *test_name, const fenv_t *envp, int fe_exc, |
202 | int fe_exc_clear, int exception) |
203 | { |
204 | char str[200]; |
205 | /* The standard allows the inexact exception to be set together with the |
206 | underflow and overflow exceptions. So ignore the inexact flag if the |
207 | others are raised. */ |
208 | int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0; |
209 | |
210 | strcpy (dest: str, src: test_name); |
211 | strcat (dest: str, src: ": set flag, with rest not set" ); |
212 | feclearexcept (FE_ALL_EXCEPT); |
213 | feraiseexcept (excepts: exception); |
214 | feupdateenv (envp: envp); |
215 | test_exceptions (test_name: str, exception: fe_exc, ignore_inexact); |
216 | |
217 | strcpy (dest: str, src: test_name); |
218 | strcat (dest: str, src: ": clear flag, rest also unset" ); |
219 | feclearexcept (excepts: exception); |
220 | feupdateenv (envp: envp); |
221 | test_exceptions (test_name: str, exception: fe_exc_clear, ignore_inexact); |
222 | } |
223 | #endif |
224 | |
225 | static void |
226 | fe_tests (void) |
227 | { |
228 | /* clear all exceptions and test if all are cleared */ |
229 | feclearexcept (FE_ALL_EXCEPT); |
230 | test_exceptions (test_name: "feclearexcept (FE_ALL_EXCEPT) clears all exceptions" , |
231 | NO_EXC, ignore_inexact: 0); |
232 | |
233 | /* Skip further tests here if exceptions not supported. */ |
234 | if (!EXCEPTION_TESTS (float) && FE_ALL_EXCEPT != 0) |
235 | return; |
236 | /* raise all exceptions and test if all are raised */ |
237 | feraiseexcept (FE_ALL_EXCEPT); |
238 | test_exceptions (test_name: "feraiseexcept (FE_ALL_EXCEPT) raises all exceptions" , |
239 | ALL_EXC, ignore_inexact: 0); |
240 | feclearexcept (FE_ALL_EXCEPT); |
241 | |
242 | #ifdef FE_DIVBYZERO |
243 | set_single_exc (test_name: "Set/Clear FE_DIVBYZERO" , DIVBYZERO_EXC, FE_DIVBYZERO); |
244 | #endif |
245 | #ifdef FE_INVALID |
246 | set_single_exc (test_name: "Set/Clear FE_INVALID" , INVALID_EXC, FE_INVALID); |
247 | #endif |
248 | #ifdef FE_INEXACT |
249 | set_single_exc (test_name: "Set/Clear FE_INEXACT" , INEXACT_EXC, FE_INEXACT); |
250 | #endif |
251 | #ifdef FE_UNDERFLOW |
252 | set_single_exc (test_name: "Set/Clear FE_UNDERFLOW" , UNDERFLOW_EXC, FE_UNDERFLOW); |
253 | #endif |
254 | #ifdef FE_OVERFLOW |
255 | set_single_exc (test_name: "Set/Clear FE_OVERFLOW" , OVERFLOW_EXC, FE_OVERFLOW); |
256 | #endif |
257 | } |
258 | |
259 | #if FE_ALL_EXCEPT |
260 | static const char * |
261 | funcname (int (*func)(const fenv_t *)) |
262 | { |
263 | if (func == fesetenv) |
264 | return "fesetenv" ; |
265 | else if (func == feupdateenv) |
266 | return "feupdateenv" ; |
267 | __builtin_unreachable (); |
268 | } |
269 | |
270 | /* Test that program aborts with no masked interrupts */ |
271 | static void |
272 | feenv_nomask_test (const char *flag_name, int fe_exc, int (*func)(const fenv_t *)) |
273 | { |
274 | # if defined FE_NOMASK_ENV |
275 | int status; |
276 | pid_t pid; |
277 | |
278 | if (!EXCEPTION_ENABLE_SUPPORTED (FE_ALL_EXCEPT) |
279 | && func (FE_NOMASK_ENV) != 0) |
280 | { |
281 | printf (format: "Test: not testing FE_NOMASK_ENV, it isn't implemented.\n" ); |
282 | return; |
283 | } |
284 | |
285 | printf (format: "Test: after %s (FE_NOMASK_ENV) processes will abort\n" , funcname (func)); |
286 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
287 | pid = fork (); |
288 | if (pid == 0) |
289 | { |
290 | # ifdef RLIMIT_CORE |
291 | /* Try to avoid dumping core. */ |
292 | struct rlimit core_limit; |
293 | core_limit.rlim_cur = 0; |
294 | core_limit.rlim_max = 0; |
295 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
296 | # endif |
297 | |
298 | fesetenv (FE_NOMASK_ENV); |
299 | feraiseexcept (excepts: fe_exc); |
300 | exit (status: 2); |
301 | } |
302 | else if (pid < 0) |
303 | { |
304 | if (errno != ENOSYS) |
305 | { |
306 | printf (format: " Fail: Could not fork.\n" ); |
307 | ++count_errors; |
308 | } |
309 | else |
310 | printf (format: " `fork' not implemented, test ignored.\n" ); |
311 | } |
312 | else { |
313 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
314 | { |
315 | printf (format: " Fail: waitpid call failed.\n" ); |
316 | ++count_errors; |
317 | } |
318 | else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE) |
319 | printf (format: " Pass: Process received SIGFPE.\n" ); |
320 | else |
321 | { |
322 | printf (format: " Fail: Process didn't receive signal and exited with status %d.\n" , |
323 | status); |
324 | ++count_errors; |
325 | } |
326 | } |
327 | # endif |
328 | } |
329 | |
330 | /* Test that program doesn't abort with default environment */ |
331 | static void |
332 | feenv_mask_test (const char *flag_name, int fe_exc, int (*func)(const fenv_t *)) |
333 | { |
334 | int status; |
335 | pid_t pid; |
336 | |
337 | printf (format: "Test: after %s (FE_DFL_ENV) processes will not abort\n" , funcname (func)); |
338 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
339 | pid = fork (); |
340 | if (pid == 0) |
341 | { |
342 | #ifdef RLIMIT_CORE |
343 | /* Try to avoid dumping core. */ |
344 | struct rlimit core_limit; |
345 | core_limit.rlim_cur = 0; |
346 | core_limit.rlim_max = 0; |
347 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
348 | #endif |
349 | |
350 | func (FE_DFL_ENV); |
351 | feraiseexcept (excepts: fe_exc); |
352 | exit (status: 2); |
353 | } |
354 | else if (pid < 0) |
355 | { |
356 | if (errno != ENOSYS) |
357 | { |
358 | printf (format: " Fail: Could not fork.\n" ); |
359 | ++count_errors; |
360 | } |
361 | else |
362 | printf (format: " `fork' not implemented, test ignored.\n" ); |
363 | } |
364 | else { |
365 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
366 | { |
367 | printf (format: " Fail: waitpid call failed.\n" ); |
368 | ++count_errors; |
369 | } |
370 | else if (WIFEXITED (status) && WEXITSTATUS (status) == 2) |
371 | printf (format: " Pass: Process exited normally.\n" ); |
372 | else |
373 | { |
374 | printf (format: " Fail: Process exited abnormally with status %d.\n" , |
375 | status); |
376 | ++count_errors; |
377 | } |
378 | } |
379 | } |
380 | |
381 | /* Test that program aborts with no masked interrupts */ |
382 | static void |
383 | feexcp_nomask_test (const char *flag_name, int fe_exc) |
384 | { |
385 | int status; |
386 | pid_t pid; |
387 | |
388 | if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && feenableexcept (excepts: fe_exc) == -1) |
389 | { |
390 | printf (format: "Test: not testing feenableexcept, it isn't implemented.\n" ); |
391 | return; |
392 | } |
393 | |
394 | printf (format: "Test: after feenableexcept (%s) processes will abort\n" , |
395 | flag_name); |
396 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
397 | pid = fork (); |
398 | if (pid == 0) |
399 | { |
400 | #ifdef RLIMIT_CORE |
401 | /* Try to avoid dumping core. */ |
402 | struct rlimit core_limit; |
403 | core_limit.rlim_cur = 0; |
404 | core_limit.rlim_max = 0; |
405 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
406 | #endif |
407 | |
408 | fedisableexcept (FE_ALL_EXCEPT); |
409 | feenableexcept (excepts: fe_exc); |
410 | feraiseexcept (excepts: fe_exc); |
411 | exit (status: 2); |
412 | } |
413 | else if (pid < 0) |
414 | { |
415 | if (errno != ENOSYS) |
416 | { |
417 | printf (format: " Fail: Could not fork.\n" ); |
418 | ++count_errors; |
419 | } |
420 | else |
421 | printf (format: " `fork' not implemented, test ignored.\n" ); |
422 | } |
423 | else { |
424 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
425 | { |
426 | printf (format: " Fail: waitpid call failed.\n" ); |
427 | ++count_errors; |
428 | } |
429 | else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE) |
430 | printf (format: " Pass: Process received SIGFPE.\n" ); |
431 | else |
432 | { |
433 | printf (format: " Fail: Process didn't receive signal and exited with status %d.\n" , |
434 | status); |
435 | ++count_errors; |
436 | } |
437 | } |
438 | } |
439 | |
440 | /* Test that program doesn't abort with exception. */ |
441 | static void |
442 | feexcp_mask_test (const char *flag_name, int fe_exc) |
443 | { |
444 | int status; |
445 | int exception; |
446 | pid_t pid; |
447 | |
448 | printf (format: "Test: after fedisableexcept (%s) processes will not abort\n" , |
449 | flag_name); |
450 | printf (format: " when feraiseexcept (%s) is called.\n" , flag_name); |
451 | pid = fork (); |
452 | if (pid == 0) |
453 | { |
454 | #ifdef RLIMIT_CORE |
455 | /* Try to avoid dumping core. */ |
456 | struct rlimit core_limit; |
457 | core_limit.rlim_cur = 0; |
458 | core_limit.rlim_max = 0; |
459 | setrlimit (RLIMIT_CORE, rlimits: &core_limit); |
460 | #endif |
461 | feenableexcept (FE_ALL_EXCEPT); |
462 | exception = fe_exc; |
463 | #ifdef FE_INEXACT |
464 | /* The standard allows the inexact exception to be set together with the |
465 | underflow and overflow exceptions. So add FE_INEXACT to the set of |
466 | exceptions to be disabled if we will be raising underflow or |
467 | overflow. */ |
468 | # ifdef FE_OVERFLOW |
469 | if (fe_exc & FE_OVERFLOW) |
470 | exception |= FE_INEXACT; |
471 | # endif |
472 | # ifdef FE_UNDERFLOW |
473 | if (fe_exc & FE_UNDERFLOW) |
474 | exception |= FE_INEXACT; |
475 | # endif |
476 | #endif |
477 | fedisableexcept (excepts: exception); |
478 | feraiseexcept (excepts: fe_exc); |
479 | exit (status: 2); |
480 | } |
481 | else if (pid < 0) |
482 | { |
483 | if (errno != ENOSYS) |
484 | { |
485 | printf (format: " Fail: Could not fork.\n" ); |
486 | ++count_errors; |
487 | } |
488 | else |
489 | printf (format: " `fork' not implemented, test ignored.\n" ); |
490 | } |
491 | else { |
492 | if (waitpid (pid: pid, stat_loc: &status, options: 0) != pid) |
493 | { |
494 | printf (format: " Fail: waitpid call failed.\n" ); |
495 | ++count_errors; |
496 | } |
497 | else if (WIFEXITED (status) && WEXITSTATUS (status) == 2) |
498 | printf (format: " Pass: Process exited normally.\n" ); |
499 | else |
500 | { |
501 | printf (format: " Fail: Process exited abnormally with status %d.\n" , |
502 | status); |
503 | ++count_errors; |
504 | } |
505 | } |
506 | } |
507 | |
508 | |
509 | /* Tests for feenableexcept/fedisableexcept/fegetexcept. */ |
510 | static void |
511 | feenable_test (const char *flag_name, int fe_exc) |
512 | { |
513 | int excepts; |
514 | |
515 | printf (format: "Tests for feenableexcepts etc. with flag %s\n" , flag_name); |
516 | |
517 | /* First disable all exceptions. */ |
518 | if (fedisableexcept (FE_ALL_EXCEPT) == -1) |
519 | { |
520 | printf (format: "Test: fedisableexcept (FE_ALL_EXCEPT) failed\n" ); |
521 | ++count_errors; |
522 | /* If this fails, the other tests don't make sense. */ |
523 | return; |
524 | } |
525 | excepts = fegetexcept (); |
526 | if (excepts != 0) |
527 | { |
528 | printf (format: "Test: fegetexcept (%s) failed, return should be 0, is %d\n" , |
529 | flag_name, excepts); |
530 | ++count_errors; |
531 | } |
532 | excepts = feenableexcept (excepts: fe_exc); |
533 | if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && excepts == -1) |
534 | { |
535 | printf (format: "Test: not testing feenableexcept, it isn't implemented.\n" ); |
536 | return; |
537 | } |
538 | if (excepts == -1) |
539 | { |
540 | printf (format: "Test: feenableexcept (%s) failed\n" , flag_name); |
541 | ++count_errors; |
542 | return; |
543 | } |
544 | if (excepts != 0) |
545 | { |
546 | printf (format: "Test: feenableexcept (%s) failed, return should be 0, is %x\n" , |
547 | flag_name, excepts); |
548 | ++count_errors; |
549 | } |
550 | |
551 | excepts = fegetexcept (); |
552 | if (excepts != fe_exc) |
553 | { |
554 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
555 | flag_name, fe_exc, excepts); |
556 | ++count_errors; |
557 | } |
558 | |
559 | /* And now disable the exception again. */ |
560 | excepts = fedisableexcept (excepts: fe_exc); |
561 | if (excepts == -1) |
562 | { |
563 | printf (format: "Test: fedisableexcept (%s) failed\n" , flag_name); |
564 | ++count_errors; |
565 | return; |
566 | } |
567 | if (excepts != fe_exc) |
568 | { |
569 | printf (format: "Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
570 | flag_name, fe_exc, excepts); |
571 | ++count_errors; |
572 | } |
573 | |
574 | excepts = fegetexcept (); |
575 | if (excepts != 0) |
576 | { |
577 | printf (format: "Test: fegetexcept (%s) failed, return should be 0, is 0x%x\n" , |
578 | flag_name, excepts); |
579 | ++count_errors; |
580 | } |
581 | |
582 | /* Now the other way round: Enable all exceptions and disable just this one. */ |
583 | if (feenableexcept (FE_ALL_EXCEPT) == -1) |
584 | { |
585 | printf (format: "Test: feenableexcept (FE_ALL_EXCEPT) failed\n" ); |
586 | ++count_errors; |
587 | /* If this fails, the other tests don't make sense. */ |
588 | return; |
589 | } |
590 | |
591 | excepts = fegetexcept (); |
592 | if (excepts != FE_ALL_EXCEPT) |
593 | { |
594 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
595 | flag_name, FE_ALL_EXCEPT, excepts); |
596 | ++count_errors; |
597 | } |
598 | |
599 | excepts = fedisableexcept (excepts: fe_exc); |
600 | if (excepts == -1) |
601 | { |
602 | printf (format: "Test: fedisableexcept (%s) failed\n" , flag_name); |
603 | ++count_errors; |
604 | return; |
605 | } |
606 | if (excepts != FE_ALL_EXCEPT) |
607 | { |
608 | printf (format: "Test: fedisableexcept (%s) failed, return should be 0, is 0x%x\n" , |
609 | flag_name, excepts); |
610 | ++count_errors; |
611 | } |
612 | |
613 | excepts = fegetexcept (); |
614 | if (excepts != (FE_ALL_EXCEPT & ~fe_exc)) |
615 | { |
616 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
617 | flag_name, (FE_ALL_EXCEPT & ~fe_exc), excepts); |
618 | ++count_errors; |
619 | } |
620 | |
621 | /* And now enable the exception again. */ |
622 | excepts = feenableexcept (excepts: fe_exc); |
623 | if (excepts == -1) |
624 | { |
625 | printf (format: "Test: feenableexcept (%s) failed\n" , flag_name); |
626 | ++count_errors; |
627 | return; |
628 | } |
629 | if (excepts != (FE_ALL_EXCEPT & ~fe_exc)) |
630 | { |
631 | printf (format: "Test: feenableexcept (%s) failed, return should be 0, is 0x%x\n" , |
632 | flag_name, excepts); |
633 | ++count_errors; |
634 | } |
635 | |
636 | excepts = fegetexcept (); |
637 | if (excepts != FE_ALL_EXCEPT) |
638 | { |
639 | printf (format: "Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n" , |
640 | flag_name, FE_ALL_EXCEPT, excepts); |
641 | ++count_errors; |
642 | } |
643 | feexcp_nomask_test (flag_name, fe_exc); |
644 | feexcp_mask_test (flag_name, fe_exc); |
645 | |
646 | } |
647 | |
648 | |
649 | static void |
650 | fe_single_test (const char *flag_name, int fe_exc) |
651 | { |
652 | feenv_nomask_test (flag_name, fe_exc, func: fesetenv); |
653 | feenv_mask_test (flag_name, fe_exc, func: fesetenv); |
654 | feenable_test (flag_name, fe_exc); |
655 | } |
656 | |
657 | |
658 | static void |
659 | feupdate_single_test (const char *flag_name, int fe_exc) |
660 | { |
661 | feenv_nomask_test (flag_name, fe_exc, func: feupdateenv); |
662 | fesetenv (FE_DFL_ENV); |
663 | feenv_mask_test (flag_name, fe_exc, func: feupdateenv); |
664 | } |
665 | #endif |
666 | |
667 | |
668 | static void |
669 | feenv_tests (void) |
670 | { |
671 | /* We might have some exceptions still set. */ |
672 | feclearexcept (FE_ALL_EXCEPT); |
673 | |
674 | #ifdef FE_DIVBYZERO |
675 | fe_single_test (flag_name: "FE_DIVBYZERO" , FE_DIVBYZERO); |
676 | #endif |
677 | #ifdef FE_INVALID |
678 | fe_single_test (flag_name: "FE_INVALID" , FE_INVALID); |
679 | #endif |
680 | #ifdef FE_INEXACT |
681 | fe_single_test (flag_name: "FE_INEXACT" , FE_INEXACT); |
682 | #endif |
683 | #ifdef FE_UNDERFLOW |
684 | fe_single_test (flag_name: "FE_UNDERFLOW" , FE_UNDERFLOW); |
685 | #endif |
686 | #ifdef FE_OVERFLOW |
687 | fe_single_test (flag_name: "FE_OVERFLOW" , FE_OVERFLOW); |
688 | #endif |
689 | fesetenv (FE_DFL_ENV); |
690 | } |
691 | |
692 | #if FE_ALL_EXCEPT |
693 | static void |
694 | feupdateenv_single_test (const char *test_name, int fe_exc, int exception) |
695 | { |
696 | char str[100]; |
697 | fenv_t env; |
698 | int res; |
699 | |
700 | snprintf (s: str, maxlen: sizeof str, format: "feupdateenv %s and FL_DFL_ENV" , test_name); |
701 | update_single_exc (test_name: str, FE_DFL_ENV, fe_exc, NO_EXC, exception); |
702 | |
703 | feraiseexcept (FE_ALL_EXCEPT); |
704 | res = fegetenv (envp: &env); |
705 | if (res != 0) |
706 | { |
707 | printf (format: "fegetenv failed: %d\n" , res); |
708 | ++count_errors; |
709 | return; |
710 | } |
711 | |
712 | snprintf (s: str, maxlen: sizeof str, format: "feupdateenv %s and FE_ALL_EXCEPT" , test_name); |
713 | update_single_exc (test_name: str, envp: &env, ALL_EXC, ALL_EXC, exception); |
714 | } |
715 | #endif |
716 | |
717 | static void |
718 | feupdateenv_tests (void) |
719 | { |
720 | /* We might have some exceptions still set. */ |
721 | feclearexcept (FE_ALL_EXCEPT); |
722 | |
723 | #ifdef FE_DIVBYZERO |
724 | feupdate_single_test (flag_name: "FE_DIVBYZERO" , FE_DIVBYZERO); |
725 | #endif |
726 | #ifdef FE_INVALID |
727 | feupdate_single_test (flag_name: "FE_INVALID" , FE_INVALID); |
728 | #endif |
729 | #ifdef FE_INEXACT |
730 | feupdate_single_test (flag_name: "FE_INEXACT" , FE_INEXACT); |
731 | #endif |
732 | #ifdef FE_UNDERFLOW |
733 | feupdate_single_test (flag_name: "FE_UNDERFLOW" , FE_UNDERFLOW); |
734 | #endif |
735 | #ifdef FE_OVERFLOW |
736 | feupdate_single_test (flag_name: "FE_OVERFLOW" , FE_OVERFLOW); |
737 | #endif |
738 | |
739 | #ifdef FE_DIVBYZERO |
740 | feupdateenv_single_test (test_name: "DIVBYZERO" , DIVBYZERO_EXC, FE_DIVBYZERO); |
741 | #endif |
742 | #ifdef FE_INVALID |
743 | feupdateenv_single_test (test_name: "INVALID" , INVALID_EXC, FE_INVALID); |
744 | #endif |
745 | #ifdef FE_INEXACT |
746 | feupdateenv_single_test (test_name: "INEXACT" , INEXACT_EXC, FE_INEXACT); |
747 | #endif |
748 | #ifdef FE_UNDERFLOW |
749 | feupdateenv_single_test (test_name: "UNDERFLOW" , UNDERFLOW_EXC, FE_UNDERFLOW); |
750 | #endif |
751 | #ifdef FE_OVERFLOW |
752 | feupdateenv_single_test (test_name: "OVERFLOW" , OVERFLOW_EXC, FE_OVERFLOW); |
753 | #endif |
754 | |
755 | feupdateenv (FE_DFL_ENV); |
756 | } |
757 | |
758 | |
759 | static void |
760 | feholdexcept_tests (void) |
761 | { |
762 | fenv_t saved, saved2; |
763 | int res; |
764 | |
765 | feclearexcept (FE_ALL_EXCEPT); |
766 | fedisableexcept (FE_ALL_EXCEPT); |
767 | #ifdef FE_DIVBYZERO |
768 | feraiseexcept (FE_DIVBYZERO); |
769 | #endif |
770 | if (EXCEPTION_TESTS (float)) |
771 | test_exceptions (test_name: "feholdexcept_tests FE_DIVBYZERO test" , |
772 | DIVBYZERO_EXC, ignore_inexact: 0); |
773 | res = feholdexcept (envp: &saved); |
774 | if (res != 0) |
775 | { |
776 | printf (format: "feholdexcept failed: %d\n" , res); |
777 | ++count_errors; |
778 | } |
779 | #if defined FE_TONEAREST && defined FE_TOWARDZERO |
780 | res = fesetround (FE_TOWARDZERO); |
781 | if (res != 0 && ROUNDING_TESTS (float, FE_TOWARDZERO)) |
782 | { |
783 | printf (format: "fesetround failed: %d\n" , res); |
784 | ++count_errors; |
785 | } |
786 | #endif |
787 | test_exceptions (test_name: "feholdexcept_tests 0 test" , NO_EXC, ignore_inexact: 0); |
788 | #ifdef FE_INVALID |
789 | feraiseexcept (FE_INVALID); |
790 | if (EXCEPTION_TESTS (float)) |
791 | test_exceptions (test_name: "feholdexcept_tests FE_INVALID test" , |
792 | INVALID_EXC, ignore_inexact: 0); |
793 | #endif |
794 | res = feupdateenv (envp: &saved); |
795 | if (res != 0) |
796 | { |
797 | printf (format: "feupdateenv failed: %d\n" , res); |
798 | ++count_errors; |
799 | } |
800 | #if defined FE_TONEAREST && defined FE_TOWARDZERO |
801 | res = fegetround (); |
802 | if (res != FE_TONEAREST) |
803 | { |
804 | printf (format: "feupdateenv didn't restore rounding mode: %d\n" , res); |
805 | ++count_errors; |
806 | } |
807 | #endif |
808 | if (EXCEPTION_TESTS (float)) |
809 | test_exceptions (test_name: "feholdexcept_tests FE_DIVBYZERO|FE_INVALID test" , |
810 | DIVBYZERO_EXC | INVALID_EXC, ignore_inexact: 0); |
811 | feclearexcept (FE_ALL_EXCEPT); |
812 | #ifdef FE_INVALID |
813 | feraiseexcept (FE_INVALID); |
814 | #endif |
815 | #if defined FE_TONEAREST && defined FE_UPWARD |
816 | res = fesetround (FE_UPWARD); |
817 | if (res != 0 && ROUNDING_TESTS (float, FE_UPWARD)) |
818 | { |
819 | printf (format: "fesetround failed: %d\n" , res); |
820 | ++count_errors; |
821 | } |
822 | #endif |
823 | res = feholdexcept (envp: &saved2); |
824 | if (res != 0) |
825 | { |
826 | printf (format: "feholdexcept failed: %d\n" , res); |
827 | ++count_errors; |
828 | } |
829 | #if defined FE_TONEAREST && defined FE_UPWARD |
830 | res = fesetround (FE_TONEAREST); |
831 | if (res != 0) |
832 | { |
833 | printf (format: "fesetround failed: %d\n" , res); |
834 | ++count_errors; |
835 | } |
836 | #endif |
837 | test_exceptions (test_name: "feholdexcept_tests 0 2nd test" , NO_EXC, ignore_inexact: 0); |
838 | #ifdef FE_INEXACT |
839 | feraiseexcept (FE_INEXACT); |
840 | if (EXCEPTION_TESTS (float)) |
841 | test_exceptions (test_name: "feholdexcept_tests FE_INEXACT test" , |
842 | INEXACT_EXC, ignore_inexact: 0); |
843 | #endif |
844 | res = feupdateenv (envp: &saved2); |
845 | if (res != 0) |
846 | { |
847 | printf (format: "feupdateenv failed: %d\n" , res); |
848 | ++count_errors; |
849 | } |
850 | #if defined FE_TONEAREST && defined FE_UPWARD |
851 | res = fegetround (); |
852 | if (res != FE_UPWARD && ROUNDING_TESTS (float, FE_UPWARD)) |
853 | { |
854 | printf (format: "feupdateenv didn't restore rounding mode: %d\n" , res); |
855 | ++count_errors; |
856 | } |
857 | fesetround (FE_TONEAREST); |
858 | #endif |
859 | if (EXCEPTION_TESTS (float)) |
860 | test_exceptions (test_name: "feholdexcept_tests FE_INEXACT|FE_INVALID test" , |
861 | INVALID_EXC | INEXACT_EXC, ignore_inexact: 0); |
862 | feclearexcept (FE_ALL_EXCEPT); |
863 | } |
864 | |
865 | |
866 | /* IEC 559 and ISO C99 define a default startup environment */ |
867 | static void |
868 | initial_tests (void) |
869 | { |
870 | test_exceptions (test_name: "Initially all exceptions should be cleared" , |
871 | NO_EXC, ignore_inexact: 0); |
872 | #ifdef FE_TONEAREST |
873 | test_rounding (test_name: "Rounding direction should be initialized to nearest" , |
874 | FE_TONEAREST); |
875 | #endif |
876 | } |
877 | |
878 | static int |
879 | do_test (void) |
880 | { |
881 | initial_tests (); |
882 | fe_tests (); |
883 | feenv_tests (); |
884 | feholdexcept_tests (); |
885 | feupdateenv_tests (); |
886 | |
887 | if (count_errors) |
888 | { |
889 | printf (format: "\n%d errors occurred.\n" , count_errors); |
890 | exit (status: 1); |
891 | } |
892 | printf (format: "\n All tests passed successfully.\n" ); |
893 | return 0; |
894 | } |
895 | |
896 | #include <support/test-driver.c> |
897 | |