1 /*
2 * sys-setjmp - wrap system setjmp or compiler C try/catch mechanism
3 *
4 * Copyright(c) 2022 Glenn Strauss gstrauss()gluelogic.com All rights reserved
5 * License: BSD 3-clause (same as lighttpd)
6 */
7 #include "first.h"
8 #include "sys-setjmp.h"
9
10 #ifndef _MSC_VER
11
12 #ifdef HAVE_SIGNAL
13 #include <signal.h> /* sig_atomic_t */
14 #else
15 typedef int sig_atomic_t;
16 #endif
17
18 #include <errno.h>
19 #include <setjmp.h> /* sigjmp_buf sigsetjmp() siglongjmp() */
20 #include "ck.h"
21
22 /*(note: would need to be thread-local to be thread-safe)*/
23 static volatile sig_atomic_t sys_setjmp_sigbus_jmp_valid;
24 #ifdef _WIN32
25 static jmp_buf sys_setjmp_sigbus_jmp_buf;
26 #else
27 static sigjmp_buf sys_setjmp_sigbus_jmp_buf;
28 #endif
29
30 __attribute_noreturn__
sys_setjmp_sigbus(int sig)31 void sys_setjmp_sigbus (int sig)
32 {
33 UNUSED(sig);
34 #ifdef _WIN32
35 if (sys_setjmp_sigbus_jmp_valid) longjmp(sys_setjmp_sigbus_jmp_buf, 1);
36 #else
37 if (sys_setjmp_sigbus_jmp_valid) siglongjmp(sys_setjmp_sigbus_jmp_buf, 1);
38 #endif
39 ck_bt_abort(__FILE__, __LINE__, "SIGBUS");
40 }
41
42 /* Note: must have configured signal handler for macros to be effective
43 * e.g. signal(SIGBUS, sys_setjmp_sigbus)
44 */
45
46 /* Note: should not 'return', 'break', 'continue', 'goto' out of try block,
47 * or else sys_setjmp_sigbus_jmp_valid will not be unset. However, those
48 * are permitted from catch block when using these macros. (In practice,
49 * unsetting sys_setjmp_sigbus_jmp_valid is not critical, since SIGBUS
50 * should not be received outside of the protected blocks, or else
51 * something (elsewhere) is missing protection to catch SIGBUS.)
52 */
53
54 /* Note: sigaction() config in server.c sets SA_NODEFER and empty signal mask
55 * so we avoid saving and restoring signal mask on systems with sigaction() */
56
57 #ifdef _WIN32
58 #define if_SYS_SETJMP_TRY() if ((sys_setjmp_sigbus_jmp_valid = \
59 !setjmp(sys_setjmp_sigbus_jmp_buf))) {
60 #elif defined(HAVE_SIGACTION)
61 #define if_SYS_SETJMP_TRY() if ((sys_setjmp_sigbus_jmp_valid = \
62 !sigsetjmp(sys_setjmp_sigbus_jmp_buf, 0))) {
63 #else
64 #define if_SYS_SETJMP_TRY() if ((sys_setjmp_sigbus_jmp_valid = \
65 !sigsetjmp(sys_setjmp_sigbus_jmp_buf, 1))) {
66 #endif
67
68 #define else_SYS_SETJMP_CATCH() } \
69 else { \
70
71 #define fi_SYS_SETJMP_END() } \
72 sys_setjmp_sigbus_jmp_valid = 0;
73
74 #else /* _MSC_VER */
75
76 #include <windows.h> /* winnt.h EXCEPTION_IN_PAGE_ERROR */
77 #include <excpt.h>
78
79 #define if_SYS_SETJMP_TRY() __try {
80
81 #define else_SYS_SETJMP_CATCH() } \
82 __except ( \
83 GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR \
84 ? EXCEPTION_EXECUTE_HANDLER \
85 : EXCEPTION_CONTINUE_SEARCH ) {
86
87 #define fi_SYS_SETJMP_END() }
88
89 #endif /* _MSC_VER */
90
sys_setjmp_eval3(off_t (* cb)(void *,const void *,off_t),void * dst,const void * src,off_t len)91 off_t sys_setjmp_eval3(off_t(*cb)(void *, const void *, off_t), void *dst, const void *src, off_t len)
92 {
93 off_t rv;
94 if_SYS_SETJMP_TRY()
95 rv = cb(dst, src, len);
96 else_SYS_SETJMP_CATCH() {
97 #ifndef _MSC_VER
98 errno = EFAULT;
99 #endif
100 return -1;
101 }
102 fi_SYS_SETJMP_END()
103 return rv;
104 }
105