xref: /lighttpd1.4/src/sys-setjmp.c (revision 6cd3b5f8)
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