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__ 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 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