1 //===-- Unittests for feraiseexcept with exceptions enabled ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/fenv/feclearexcept.h"
10 #include "src/fenv/feraiseexcept.h"
11 #include "src/fenv/fetestexcept.h"
12 
13 #include "src/__support/FPUtil/FEnvUtils.h"
14 #include "src/__support/FPUtil/FPExceptMatcher.h"
15 #include "utils/UnitTest/Test.h"
16 
17 #include <fenv.h>
18 #include <signal.h>
19 
20 // This test enables an exception and verifies that raising that exception
21 // triggers SIGFPE.
22 TEST(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
23 #ifdef __aarch64__
24   // Few aarch64 HW implementations do not trap exceptions. We skip this test
25   // completely on such HW.
26   //
27   // Whether HW supports trapping exceptions or not is deduced by enabling an
28   // exception and reading back to see if the exception got enabled. If the
29   // exception did not get enabled, then it means that the HW does not support
30   // trapping exceptions.
31   __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
32   __llvm_libc::fputil::enableExcept(FE_DIVBYZERO);
33   if (__llvm_libc::fputil::getExcept() == 0)
34     return;
35 #endif
36 
37   // TODO: Install a floating point exception handler and verify that the
38   // the expected exception was raised. One will have to longjmp back from
39   // that exception handler, so such a testing can be done after we have
40   // longjmp implemented.
41 
42   int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
43                    FE_UNDERFLOW};
44 
45   // We '|' the individual exception flags instead of using FE_ALL_EXCEPT
46   // as it can include non-standard extensions. Note that we should be able
47   // to compile this file with headers from other libcs as well.
48   constexpr int allExcepts =
49       FE_DIVBYZERO | FE_INVALID | FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW;
50 
51   for (int e : excepts) {
52     __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
53     __llvm_libc::fputil::enableExcept(e);
54     ASSERT_EQ(__llvm_libc::feclearexcept(FE_ALL_EXCEPT), 0);
55     // Raising all exceptions except |e| should not call the
56     // SIGFPE handler. They should set the exception flag though,
57     // so we verify that. Since other exceptions like FE_DIVBYZERO
58     // can raise FE_INEXACT as well, we don't verify the other
59     // exception flags when FE_INEXACT is enabled.
60     if (e != FE_INEXACT) {
61       int others = allExcepts & ~e;
62       ASSERT_EQ(__llvm_libc::feraiseexcept(others), 0);
63       ASSERT_EQ(__llvm_libc::fetestexcept(others), others);
64     }
65 
66     ASSERT_RAISES_FP_EXCEPT([=] {
67       // In test frameworks like Fuchsia's zxtest, this translates to
68       // a death test which runs this closure in a different thread. So,
69       // we enable the exception again inside this closure so that the
70       // exception gets enabled for the thread running this closure.
71       __llvm_libc::fputil::enableExcept(e);
72       __llvm_libc::feraiseexcept(e);
73     });
74 
75     // Cleanup.
76     __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
77     ASSERT_EQ(__llvm_libc::feclearexcept(FE_ALL_EXCEPT), 0);
78   }
79 }
80