1//===-- Unittests for feholdexcept 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 "hdr/types/fenv_t.h"
10#include "src/fenv/feholdexcept.h"
11
12#include "src/__support/FPUtil/FEnvImpl.h"
13#include "src/__support/macros/properties/architectures.h"
14#include "test/UnitTest/FEnvSafeTest.h"
15#include "test/UnitTest/FPExceptMatcher.h"
16#include "test/UnitTest/Test.h"
17
18#include "excepts.h"
19
20using LlvmLibcFEnvTest = LIBC_NAMESPACE::testing::FEnvSafeTest;
21
22TEST_F(LlvmLibcFEnvTest, RaiseAndCrash) {
23#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || \
24 defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
25 // Few Arm HW implementations do not trap exceptions. We skip this test
26 // completely on such HW.
27 //
28 // Whether HW supports trapping exceptions or not is deduced by enabling an
29 // exception and reading back to see if the exception got enabled. If the
30 // exception did not get enabled, then it means that the HW does not support
31 // trapping exceptions.
32 LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
33 LIBC_NAMESPACE::fputil::enable_except(FE_DIVBYZERO);
34 if (LIBC_NAMESPACE::fputil::get_except() == 0)
35 return;
36#endif // Architectures where exception trapping is not supported
37
38 int excepts[] = {FE_DIVBYZERO, FE_INVALID, FE_INEXACT, FE_OVERFLOW,
39 FE_UNDERFLOW};
40
41 for (int e : excepts) {
42 fenv_t env;
43 LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
44 LIBC_NAMESPACE::fputil::enable_except(excepts: e);
45 ASSERT_EQ(LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT), 0);
46 ASSERT_EQ(LIBC_NAMESPACE::feholdexcept(&env), 0);
47 // feholdexcept should disable all excepts so raising an exception
48 // should not crash/invoke the exception handler.
49 ASSERT_EQ(LIBC_NAMESPACE::fputil::raise_except(e), 0);
50
51 ASSERT_RAISES_FP_EXCEPT([=] {
52 // When we put back the saved env, which has the exception enabled, it
53 // should crash with SIGFPE. Note that we set the old environment
54 // back inside this closure because in some test frameworks like Fuchsia's
55 // zxtest, this test translates to a death test in which this closure is
56 // run in a different thread. So, we set the old environment inside
57 // this closure so that the exception gets enabled for the thread running
58 // this closure.
59 LIBC_NAMESPACE::fputil::set_env(&env);
60 LIBC_NAMESPACE::fputil::raise_except(e);
61 });
62
63 // Cleanup
64 LIBC_NAMESPACE::fputil::disable_except(FE_ALL_EXCEPT);
65 ASSERT_EQ(LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT), 0);
66 }
67}
68

source code of libc/test/src/fenv/feholdexcept_test.cpp