xref: /llvm-project/libc/test/src/fenv/enabled_exceptions_test.cpp (revision 837dab96d6f5bece79fd58d28ea2e6f7c0912493)
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/FEnvImpl.h"
14 #include "src/__support/macros/properties/architectures.h"
15 #include "test/UnitTest/FEnvSafeTest.h"
16 #include "test/UnitTest/FPExceptMatcher.h"
17 #include "test/UnitTest/Test.h"
18 
19 #include "hdr/fenv_macros.h"
20 #include <signal.h>
21 
22 #include "excepts.h"
23 
24 using LlvmLibcExceptionStatusTest = LIBC_NAMESPACE::testing::FEnvSafeTest;
25 
26 // This test enables an exception and verifies that raising that exception
27 // triggers SIGFPE.
TEST_F(LlvmLibcExceptionStatusTest,RaiseAndCrash)28 TEST_F(LlvmLibcExceptionStatusTest, RaiseAndCrash) {
29 #if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) ||                                    \
30     defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
31   // Few Arm HW implementations do not trap exceptions. We skip this test
32   // completely on such HW.
33   //
34   // Whether HW supports trapping exceptions or not is deduced by enabling an
35   // exception and reading back to see if the exception got enabled. If the
36   // exception did not get enabled, then it means that the HW does not support
37   // trapping exceptions.
38   LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
39   LIBC_NAMESPACE::fputil::enable_except(FE_DIVBYZERO);
40   if (LIBC_NAMESPACE::fputil::get_except() == 0)
41     return;
42 #endif // Architectures where exception trapping is not supported
43 
44   // TODO: Install a floating point exception handler and verify that the
45   // the expected exception was raised. One will have to longjmp back from
46   // that exception handler, so such a testing can be done after we have
47   // longjmp implemented.
48 
49   for (int e : EXCEPTS) {
50     LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
51     LIBC_NAMESPACE::fputil::enable_except(e);
52     ASSERT_EQ(LIBC_NAMESPACE::feclearexcept(FE_ALL_EXCEPT), 0);
53     // Raising all exceptions except |e| should not call the
54     // SIGFPE handler. They should set the exception flag though,
55     // so we verify that. Since other exceptions like FE_DIVBYZERO
56     // can raise FE_INEXACT as well, we don't verify the other
57     // exception flags when FE_INEXACT is enabled.
58     if (e != FE_INEXACT) {
59       int others = ALL_EXCEPTS & ~e;
60       ASSERT_EQ(LIBC_NAMESPACE::feraiseexcept(others), 0);
61       ASSERT_EQ(LIBC_NAMESPACE::fetestexcept(others), others);
62     }
63 
64     ASSERT_RAISES_FP_EXCEPT([=] {
65       // In test frameworks like Fuchsia's zxtest, this translates to
66       // a death test which runs this closure in a different thread. So,
67       // we enable the exception again inside this closure so that the
68       // exception gets enabled for the thread running this closure.
69       LIBC_NAMESPACE::fputil::enable_except(e);
70       LIBC_NAMESPACE::feraiseexcept(e);
71     });
72 
73     // Cleanup.
74     LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
75     ASSERT_EQ(LIBC_NAMESPACE::feclearexcept(FE_ALL_EXCEPT), 0);
76   }
77 }
78