1*6c3f53c7SSiva Chandra Reddy //===-- FPExceptMatchers.cpp ----------------------------------------------===//
2*6c3f53c7SSiva Chandra Reddy //
3*6c3f53c7SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*6c3f53c7SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5*6c3f53c7SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*6c3f53c7SSiva Chandra Reddy //
7*6c3f53c7SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8*6c3f53c7SSiva Chandra Reddy 
9*6c3f53c7SSiva Chandra Reddy #include "FPExceptMatcher.h"
10*6c3f53c7SSiva Chandra Reddy 
11*6c3f53c7SSiva Chandra Reddy #include <fenv.h>
12*6c3f53c7SSiva Chandra Reddy #include <memory>
13*6c3f53c7SSiva Chandra Reddy #include <setjmp.h>
14*6c3f53c7SSiva Chandra Reddy #include <signal.h>
15*6c3f53c7SSiva Chandra Reddy 
16*6c3f53c7SSiva Chandra Reddy namespace __llvm_libc {
17*6c3f53c7SSiva Chandra Reddy namespace fputil {
18*6c3f53c7SSiva Chandra Reddy namespace testing {
19*6c3f53c7SSiva Chandra Reddy 
20*6c3f53c7SSiva Chandra Reddy #if defined(_WIN32)
21*6c3f53c7SSiva Chandra Reddy #define sigjmp_buf jmp_buf
22*6c3f53c7SSiva Chandra Reddy #define sigsetjmp(buf, save) setjmp(buf)
23*6c3f53c7SSiva Chandra Reddy #define siglongjmp(buf, val) longjmp(buf, val)
24*6c3f53c7SSiva Chandra Reddy #endif
25*6c3f53c7SSiva Chandra Reddy 
26*6c3f53c7SSiva Chandra Reddy static thread_local sigjmp_buf jumpBuffer;
27*6c3f53c7SSiva Chandra Reddy static thread_local bool caughtExcept;
28*6c3f53c7SSiva Chandra Reddy 
sigfpeHandler(int sig)29*6c3f53c7SSiva Chandra Reddy static void sigfpeHandler(int sig) {
30*6c3f53c7SSiva Chandra Reddy   caughtExcept = true;
31*6c3f53c7SSiva Chandra Reddy   siglongjmp(jumpBuffer, -1);
32*6c3f53c7SSiva Chandra Reddy }
33*6c3f53c7SSiva Chandra Reddy 
FPExceptMatcher(FunctionCaller * func)34*6c3f53c7SSiva Chandra Reddy FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) {
35*6c3f53c7SSiva Chandra Reddy   auto oldSIGFPEHandler = signal(SIGFPE, &sigfpeHandler);
36*6c3f53c7SSiva Chandra Reddy   std::unique_ptr<FunctionCaller> funcUP(func);
37*6c3f53c7SSiva Chandra Reddy 
38*6c3f53c7SSiva Chandra Reddy   caughtExcept = false;
39*6c3f53c7SSiva Chandra Reddy   fenv_t oldEnv;
40*6c3f53c7SSiva Chandra Reddy   fegetenv(&oldEnv);
41*6c3f53c7SSiva Chandra Reddy   if (sigsetjmp(jumpBuffer, 1) == 0)
42*6c3f53c7SSiva Chandra Reddy     funcUP->call();
43*6c3f53c7SSiva Chandra Reddy   // We restore the previous floating point environment after
44*6c3f53c7SSiva Chandra Reddy   // the call to the function which can potentially raise SIGFPE.
45*6c3f53c7SSiva Chandra Reddy   fesetenv(&oldEnv);
46*6c3f53c7SSiva Chandra Reddy   signal(SIGFPE, oldSIGFPEHandler);
47*6c3f53c7SSiva Chandra Reddy   exceptionRaised = caughtExcept;
48*6c3f53c7SSiva Chandra Reddy }
49*6c3f53c7SSiva Chandra Reddy 
50*6c3f53c7SSiva Chandra Reddy } // namespace testing
51*6c3f53c7SSiva Chandra Reddy } // namespace fputil
52*6c3f53c7SSiva Chandra Reddy } // namespace __llvm_libc
53