Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/lib/system/fault.cpp
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#include "system/fault.h"
5
6
#include "common/config.h"
7
#include "common/defines.h"
8
#include "common/spdlog.h"
9
#include "system/stacktrace.h"
10
11
#include <atomic>
12
#include <csetjmp>
13
#include <csignal>
14
#include <cstdint>
15
#include <utility>
16
17
#if WASMEDGE_OS_WINDOWS
18
#include "system/winapi.h"
19
#endif
20
21
namespace WasmEdge {
22
23
namespace {
24
25
std::atomic_uint handlerCount = 0;
26
thread_local Fault *localHandler = nullptr;
27
28
#if defined(SA_SIGINFO)
29
0
void signalHandler(int Signal, siginfo_t *Siginfo, void *) {
30
0
  {
31
    // Unblock current signal
32
0
    sigset_t Set;
33
0
    sigemptyset(&Set);
34
0
    sigaddset(&Set, Signal);
35
0
    pthread_sigmask(SIG_UNBLOCK, &Set, nullptr);
36
0
  }
37
0
  switch (Signal) {
38
0
  case SIGBUS:
39
0
  case SIGSEGV:
40
0
    Fault::emitFault(ErrCode::Value::MemoryOutOfBounds);
41
0
  case SIGFPE:
42
0
    assuming(Siginfo->si_code == FPE_INTDIV);
43
0
    Fault::emitFault(ErrCode::Value::DivideByZero);
44
0
  default:
45
0
    assumingUnreachable();
46
0
  }
47
0
}
48
49
0
void enableHandler() noexcept {
50
0
  struct sigaction Action {};
51
0
  Action.sa_sigaction = &signalHandler;
52
0
  Action.sa_flags = SA_SIGINFO;
53
0
  sigaction(SIGFPE, &Action, nullptr);
54
0
  sigaction(SIGBUS, &Action, nullptr);
55
0
  sigaction(SIGSEGV, &Action, nullptr);
56
0
}
57
58
0
void disableHandler() noexcept {
59
0
  std::signal(SIGFPE, SIG_DFL);
60
0
  std::signal(SIGBUS, SIG_DFL);
61
0
  std::signal(SIGSEGV, SIG_DFL);
62
0
}
63
64
#elif WASMEDGE_OS_WINDOWS
65
66
winapi::LONG_ WASMEDGE_WINAPI_WINAPI_CC
67
vectoredExceptionHandler(winapi::PEXCEPTION_POINTERS_ ExceptionInfo) {
68
  const winapi::DWORD_ Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
69
  switch (Code) {
70
  case winapi::EXCEPTION_INT_DIVIDE_BY_ZERO_:
71
    Fault::emitFault(ErrCode::Value::DivideByZero);
72
  case winapi::EXCEPTION_INT_OVERFLOW_:
73
    Fault::emitFault(ErrCode::Value::IntegerOverflow);
74
  case winapi::EXCEPTION_ACCESS_VIOLATION_:
75
    Fault::emitFault(ErrCode::Value::MemoryOutOfBounds);
76
  }
77
  return winapi::EXCEPTION_CONTINUE_EXECUTION_;
78
}
79
80
void *HandlerHandle = nullptr;
81
82
void enableHandler() noexcept {
83
  HandlerHandle =
84
      winapi::AddVectoredExceptionHandler(1, &vectoredExceptionHandler);
85
}
86
87
void disableHandler() noexcept {
88
  winapi::RemoveVectoredExceptionHandler(HandlerHandle);
89
}
90
91
#endif
92
93
0
void increaseHandler() noexcept {
94
0
  if (handlerCount++ == 0) {
95
0
    enableHandler();
96
0
  }
97
0
}
98
99
0
void decreaseHandler() noexcept {
100
0
  if (--handlerCount == 0) {
101
0
    disableHandler();
102
0
  }
103
0
}
104
105
} // namespace
106
107
0
Fault::Fault() {
108
0
  Prev = std::exchange(localHandler, this);
109
0
  increaseHandler();
110
0
}
111
112
0
Fault::~Fault() noexcept {
113
0
  decreaseHandler();
114
0
  localHandler = std::exchange(Prev, nullptr);
115
0
}
116
117
0
[[noreturn]] void Fault::emitFault(ErrCode Error) {
118
0
  assuming(localHandler != nullptr);
119
0
  auto Buffer = stackTrace(localHandler->StackTraceBuffer);
120
0
  localHandler->StackTraceSize = Buffer.size();
121
0
  longjmp(localHandler->Buffer, static_cast<int>(Error.operator uint32_t()));
122
0
}
123
124
} // namespace WasmEdge