1 //===-- FPExceptMatchers.cpp ----------------------------------------------===//
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 "FPExceptMatcher.h"
10 
11 #include <fenv.h>
12 #include <memory>
13 #include <setjmp.h>
14 #include <signal.h>
15 
16 namespace __llvm_libc {
17 namespace fputil {
18 namespace testing {
19 
20 #if defined(_WIN32)
21 #define sigjmp_buf jmp_buf
22 #define sigsetjmp(buf, save) setjmp(buf)
23 #define siglongjmp(buf, val) longjmp(buf, val)
24 #endif
25 
26 static thread_local sigjmp_buf jumpBuffer;
27 static thread_local bool caughtExcept;
28 
29 static void sigfpeHandler(int sig) {
30   caughtExcept = true;
31   siglongjmp(jumpBuffer, -1);
32 }
33 
34 FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) {
35   auto oldSIGFPEHandler = signal(SIGFPE, &sigfpeHandler);
36   std::unique_ptr<FunctionCaller> funcUP(func);
37 
38   caughtExcept = false;
39   fenv_t oldEnv;
40   fegetenv(&oldEnv);
41   if (sigsetjmp(jumpBuffer, 1) == 0)
42     funcUP->call();
43   // We restore the previous floating point environment after
44   // the call to the function which can potentially raise SIGFPE.
45   fesetenv(&oldEnv);
46   signal(SIGFPE, oldSIGFPEHandler);
47   exceptionRaised = caughtExcept;
48 }
49 
50 } // namespace testing
51 } // namespace fputil
52 } // namespace __llvm_libc
53