FFmpeg
signal.c
Go to the documentation of this file.
1 /*
2  * Copyright © 2025, Niklas Haas
3  * Copyright © 2018, VideoLAN and dav1d authors
4  * Copyright © 2018, Two Orioles, LLC
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <assert.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 
33 #include "checkasm_config.h"
34 
35 #include "checkasm/test.h"
36 #include "internal.h"
37 
38 #ifdef _WIN32
39  #include <windows.h>
40  #ifndef SIGBUS
41  /* non-standard, use the same value as mingw-w64 */
42  #define SIGBUS 10
43  #endif
44 #endif
45 
47 
48 static volatile sig_atomic_t sig; // SIG_ATOMIC_MAX = signal handling enabled
49 
50 volatile sig_atomic_t checkasm_interrupted;
51 
52 void checkasm_set_signal_handler_state(const int enabled)
53 {
54  sig = enabled ? SIG_ATOMIC_MAX : 0;
55 }
56 
57 static void interrupt_handler(const int s)
58 {
60 
61  /* If we happen to be currently executing a test function, we should jump
62  * directly out of it; since it may take an arbitrary amount of time */
63  if (sig == SIG_ATOMIC_MAX) {
64  sig = s;
66  }
67 
68  /* Don't re-set the signal handler, to let the next signal trigger the
69  * default action */
70 }
71 
72 #ifdef _WIN32
73 
74  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
75 static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e)
76 {
77  if (sig == SIG_ATOMIC_MAX) {
78  int s;
79  switch (e->ExceptionRecord->ExceptionCode) {
80  case EXCEPTION_FLT_DIVIDE_BY_ZERO:
81  case EXCEPTION_INT_DIVIDE_BY_ZERO: s = SIGFPE; break;
82  case EXCEPTION_ILLEGAL_INSTRUCTION:
83  case EXCEPTION_PRIV_INSTRUCTION: s = SIGILL; break;
84  case EXCEPTION_ACCESS_VIOLATION:
85  case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
86  case EXCEPTION_DATATYPE_MISALIGNMENT:
87  case EXCEPTION_STACK_OVERFLOW: s = SIGSEGV; break;
88  case EXCEPTION_IN_PAGE_ERROR: s = SIGBUS; break;
89  default: return EXCEPTION_CONTINUE_SEARCH;
90  }
91  sig = s;
93  }
94  return EXCEPTION_CONTINUE_SEARCH;
95 }
96  #endif
97 
98 #elif HAVE_SIGACTION && defined(SA_RESETHAND)
99 
100 static void signal_handler(int s);
101 
102 static const struct sigaction interrupt_handler_act = {
103  .sa_handler = interrupt_handler,
104  .sa_flags = SA_RESETHAND,
105 };
106 
107 static const struct sigaction signal_handler_act = {
108  .sa_handler = signal_handler,
109  .sa_flags = SA_RESETHAND,
110 };
111 
112 static void signal_handler(const int s)
113 {
114  if (sig == SIG_ATOMIC_MAX) {
115  sig = s;
116  sigaction(s, &signal_handler_act, NULL);
118  }
119 }
120 #else
121 
122 static void signal_handler(const int s)
123 {
124  if (sig == SIG_ATOMIC_MAX) {
125  sig = s;
126  signal(s, signal_handler);
128  }
129 }
130 #endif
131 
133 {
134  static int handlers_set;
135  if (handlers_set)
136  return;
137 
138 #ifdef _WIN32
139  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
140  AddVectoredExceptionHandler(0, signal_handler);
141  #endif
142  signal(SIGINT, interrupt_handler);
143  signal(SIGTERM, interrupt_handler);
144 #elif HAVE_SIGACTION && defined(SA_RESETHAND)
145 #ifdef SIGBUS
146  sigaction(SIGBUS, &signal_handler_act, NULL);
147 #endif
148  sigaction(SIGFPE, &signal_handler_act, NULL);
149  sigaction(SIGILL, &signal_handler_act, NULL);
150  sigaction(SIGSEGV, &signal_handler_act, NULL);
151  sigaction(SIGINT, &interrupt_handler_act, NULL);
152  sigaction(SIGTERM, &interrupt_handler_act, NULL);
153 #else
154 #ifdef SIGBUS
155  signal(SIGBUS, signal_handler);
156 #endif
157  signal(SIGFPE, signal_handler);
158  signal(SIGILL, signal_handler);
159  signal(SIGSEGV, signal_handler);
160  signal(SIGINT, interrupt_handler);
161  signal(SIGTERM, interrupt_handler);
162 #endif
163 
164  handlers_set = 1;
165 }
166 
168 {
169  switch (sig) {
170  case SIGFPE: return "fatal arithmetic error";
171  case SIGILL: return "illegal instruction";
172 #ifdef SIGBUS
173  case SIGBUS: return "bus error";
174 #endif
175  case SIGSEGV: return "segmentation fault";
176  case SIGINT: return "interrupted";
177  case SIGTERM: return "terminated";
178  default: return NULL;
179  }
180 }
COLD
#define COLD
Definition: internal.h:45
checkasm_config.h
checkasm_context
checkasm_jmp_buf checkasm_context
Definition: signal.c:46
checkasm_load_context
#define checkasm_load_context(ctx)
Definition: longjmp.h:68
checkasm_set_signal_handler_state
void checkasm_set_signal_handler_state(const int enabled)
Enable or disable signal handling.
Definition: signal.c:52
sig
static volatile sig_atomic_t sig
Definition: signal.c:48
s
#define s(width, name)
Definition: cbs_vp9.c:198
NULL
#define NULL
Definition: coverity.c:32
checkasm_set_signal_handlers
COLD void checkasm_set_signal_handlers(void)
Definition: signal.c:132
test.h
Test writing API for checkasm.
interrupt_handler
static void interrupt_handler(const int s)
Definition: signal.c:57
checkasm_jmp_buf
jmp_buf checkasm_jmp_buf
Definition: longjmp.h:66
checkasm_interrupted
volatile sig_atomic_t checkasm_interrupted
Definition: signal.c:50
checkasm_get_last_signal_desc
const char * checkasm_get_last_signal_desc(void)
Definition: signal.c:167
internal.h
signal_handler
static void signal_handler(const int s)
Definition: signal.c:122