From 79f9dcb2893903a7f66d9256d86c52ba4982652b Mon Sep 17 00:00:00 2001 From: verhaegs Date: Sun, 9 Sep 2012 00:46:05 +0000 Subject: [PATCH] arosc.library: Centralized exit handling code in __arosc_startup.c * Added autodocs for __arosc_program_start() and __arosc_program_end() * Added functions: * __arosc_set_errorptr() * __arosc_set_exitjmp() * __arosc_ * Use new functions to try to only access the aroscbase fields in __arosc_startup.c. __arosc_nixcmain.c is still left. * Fixed regression in vfork() that access udata after it was freed (spank me). git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@45756 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- compiler/clib/__arosc_startup.c | 216 ++++++++++++++++++++++++++++++++++++-- compiler/clib/__signal.c | 5 +- compiler/clib/__vfork.c | 60 +++++------ compiler/clib/__vfork.h | 9 +- compiler/clib/_exit.c | 8 +- compiler/clib/abort.c | 5 +- compiler/clib/arosc.conf | 3 + compiler/clib/exit.c | 11 +- compiler/clib/include/sys/arosc.h | 3 + 9 files changed, 257 insertions(+), 63 deletions(-) diff --git a/compiler/clib/__arosc_startup.c b/compiler/clib/__arosc_startup.c index 3f3a94a3b2..6ef4561e65 100644 --- a/compiler/clib/__arosc_startup.c +++ b/compiler/clib/__arosc_startup.c @@ -5,23 +5,61 @@ Desc: arosc library - support code for entering and leaving a program Lang: english */ -#include "__arosc_privdata.h" -#include "__exitfunc.h" +#include +#include +#include +#include + +#include +#include #define DEBUG 0 #include -#include -#include +#include "__arosc_privdata.h" +#include "__exitfunc.h" + +/***************************************************************************** + + NAME */ + void __arosc_program_startup( -void __arosc_program_startup(jmp_buf exitjmp, int *error_ptr) +/* SYNOPSIS */ + jmp_buf exitjmp, + int *errorptr) + +/* FUNCTION + This is called during program startup and before calling main. + This is to allow arosc.library to do some initialization that couldn't + be done when opening the library. + + INPUTS + exitjmp - jmp_buf to jump to to exit the program + errorptr - pointer to store return value of program + + RESULT + - + + NOTES + This function is normally called by the startup code so one + should not need to do it oneself. + + EXAMPLE + + BUGS + + SEE ALSO + + INTERNALS + +******************************************************************************/ { struct aroscbase *aroscbase = __aros_getbase(); struct Process *me = (struct Process *)FindTask(NULL); D(bug("[__arosc_program_startup] aroscbase 0x%p\n", aroscbase)); - aroscbase->acb_startup_error_ptr = error_ptr; + aroscbase->acb_startup_error_ptr = errorptr; *aroscbase->acb_exit_jmp_buf = *exitjmp; /* A some C error IO routines evidently rely on this, and @@ -34,7 +72,39 @@ void __arosc_program_startup(jmp_buf exitjmp, int *error_ptr) } } -void __arosc_program_end(void) +/***************************************************************************** + + NAME */ + void __arosc_program_end( + +/* SYNOPSIS */ + void) + +/* FUNCTION + This function is to be called when main() has returned or after + program has exited. This allows to arosc.library to do some + cleanup that can't be done during closing of the library. + + INPUTS + - + + RESULT + - + + NOTES + This function is normally called by the startup code so one + should not need to do it oneself. + + EXAMPLE + + BUGS + + SEE ALSO + + INTERNALS + + +******************************************************************************/ { struct aroscbase *aroscbase = __aros_getbase(); D(bug("[__arosc_program_end]\n")); @@ -42,3 +112,135 @@ void __arosc_program_end(void) if (!(aroscbase->acb_flags & ABNORMAL_EXIT)) __callexitfuncs(); } + +/***************************************************************************** + + NAME */ + int *__arosc_set_errorptr( + +/* SYNOPSIS */ + int *errorptr) + +/* FUNCTION + This function sets the pointer to store error return value for + program exit. + + INPUTS + errorptr - new pointer to return value + + RESULT + old pointer to return value + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + + INTERNALS + +******************************************************************************/ +{ + struct aroscbase *aroscbase = __aros_getbase(); + int *old = aroscbase->acb_startup_error_ptr; + + aroscbase->acb_startup_error_ptr = errorptr; + + return old; +} + +/***************************************************************************** + + NAME */ + void __arosc_set_exitjmp( + +/* SYNOPSIS */ + jmp_buf exitjmp, + jmp_buf previousjmp) + +/* FUNCTION + This function set the jmp_buf to use for directly exiting current + program. + + INPUTS + exitjmp - new jmp_buf for exiting + + RESULT + previous jmp_buf for exiting + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + + INTERNALS + +******************************************************************************/ +{ + struct aroscbase *aroscbase = __aros_getbase(); + + *previousjmp = *aroscbase->acb_exit_jmp_buf; + *aroscbase->acb_exit_jmp_buf = *exitjmp; +} + +/***************************************************************************** + + NAME */ + void __arosc_jmp2exit( + +/* SYNOPSIS */ + int normal, + int retcode) + +/* FUNCTION + This function directly jumps to the exit of a program. + + INPUTS + normal - Indicates if exit is normal or not. When it is abnormal no + atexit functions will be called. + retcode - the return code for the program. + + RESULT + - + + NOTES + In normal operation this function does not return. + If this function returns it means that this function was called in a + context where jmp_buf for exit was not initialized. Likely cause is + a module that opened arosstdc.library. + Be sure to capture this situation. + + EXAMPLE + + BUGS + + SEE ALSO + + INTERNALS + +******************************************************************************/ +{ + struct aroscbase *aroscbase = __aros_getbase(); + + /* No __arosc_progam_startup() called; Alert() + */ + if (aroscbase->acb_startup_error_ptr == NULL) + { + kprintf("[__arosc_jmp2exit] Trying to exit without proper initialization\n"); + Alert(AT_DeadEnd | AG_BadParm); + } + + if (!normal) + aroscbase->acb_flags |= ABNORMAL_EXIT; + + *aroscbase->acb_startup_error_ptr = retcode; + + longjmp(aroscbase->acb_exit_jmp_buf, 1); + + assert(0); /* Not reached */ +} diff --git a/compiler/clib/__signal.c b/compiler/clib/__signal.c index 07c7b5725e..7445b47a76 100644 --- a/compiler/clib/__signal.c +++ b/compiler/clib/__signal.c @@ -50,8 +50,6 @@ struct signal_func_data *__sig_getfuncdata(int signum) /* Handler for SIG_DFL */ void __sig_default(int signum) { - struct aroscbase *aroscbase = __aros_getbase(); - switch (signum) { case SIGABRT: @@ -67,8 +65,7 @@ void __sig_default(int signum) break; } - aroscbase->acb_flags |= ABNORMAL_EXIT; - longjmp(aroscbase->acb_exit_jmp_buf, 20); + __arosc_jmp2exit(0, 20); assert(0); /* Should not be reached */ } diff --git a/compiler/clib/__vfork.c b/compiler/clib/__vfork.c index 9ef036b88e..fb051ce50d 100644 --- a/compiler/clib/__vfork.c +++ b/compiler/clib/__vfork.c @@ -75,9 +75,10 @@ LONG launcher() udata->child_aroscbase = aroscbase; aroscbase->acb_parent_does_upath = pbase->acb_doupath; - if(setjmp(aroscbase->acb_exit_jmp_buf) == 0) + if(setjmp(udata->child_exitjmp) == 0) { - + __arosc_program_startup(udata->child_exitjmp, &udata->child_error); + /* Setup complete, signal parent */ D(bug("launcher: Signaling parent that we finished setup\n")); Signal(udata->parent, 1 << udata->parent_signal); @@ -201,10 +202,6 @@ pid_t __vfork(jmp_buf env) D(bug("__vfork: Parent: Saved old parent's vfork_data: %p\n", udata->prev)); udata->parent_aroscbase = aroscbase; - D(bug("__vfork: Parent: backuping startup buffer\n")); - /* Backup startup buffer */ - *udata->arosc_exit_jmp = *aroscbase->acb_exit_jmp_buf; - D(bug("__vfork: Parent: Allocating parent signal\n")); /* Allocate signal for child->parent communication */ udata->parent_signal = AllocSignal(-1); @@ -240,11 +237,25 @@ pid_t __vfork(jmp_buf env) vfork_longjmp(env, -1); } - D(bug("__vfork: Parent: Setting jmp_buf at %p\n", aroscbase->acb_exit_jmp_buf)); - if(setjmp(aroscbase->acb_exit_jmp_buf)) + D(bug("__vfork: Parent: Setting jmp_buf at %p\n", udata->parent_newexitjmp)); + if(setjmp(udata->parent_newexitjmp) == 0) { - ULONG child_id; + udata->parent_olderrorptr = __arosc_set_errorptr(&udata->child_error); + udata->child_error = *udata->parent_olderrorptr; + __arosc_set_exitjmp(udata->parent_newexitjmp, udata->parent_oldexitjmp); + + parent_enterpretendchild(udata); + D(bug("__vfork: Child %d jumping to jmp_buf %p\n", udata->child_id, &udata->vfork_jmp)); + D(bug("__vfork: ip: %p, stack: %p alt: %p\n", udata->vfork_jmp[0].retaddr, udata->vfork_jmp[0].regs[SP], + udata->vfork_jmp[0].regs[ALT])); + + vfork_longjmp(udata->vfork_jmp, 0); + assert(0); /* not reached */ + return (pid_t) 0; + } + else /* setjmp() != 0; so child has exited() */ + { D(bug("__vfork: Child: child exiting\n or executed\n")); /* Stack may have been overwritten when we return here, @@ -258,18 +269,13 @@ pid_t __vfork(jmp_buf env) if(!udata->child_executed) { D(bug("__vfork: Child: not executed\n")); - if (udata->child_aroscbase->acb_startup_error_ptr != NULL) - { - *udata->child_aroscbase->acb_startup_error_ptr = - *aroscbase->acb_startup_error_ptr; - } /* et_Result is normally set in startup code but no exec was performed so we have to mimic the startup code */ etask = GetETask(udata->child); if (etask) - etask->et_Result1 = *aroscbase->acb_startup_error_ptr; + etask->et_Result1 = udata->child_error; D(bug("__vfork: Child: Signaling child %p, signal %d\n", udata->child, udata->child_signal)); Signal(udata->child, 1 << udata->child_signal); @@ -284,7 +290,8 @@ pid_t __vfork(jmp_buf env) D(bug("__vfork: Parent: restoring startup buffer\n")); /* Restore parent startup buffer */ - *aroscbase->acb_exit_jmp_buf = *udata->arosc_exit_jmp; + jmp_buf dummy; + __arosc_set_exitjmp(udata->parent_oldexitjmp, dummy); D(bug("__vfork: Parent: freeing parent signal\n")); FreeSignal(udata->parent_signal); @@ -293,28 +300,19 @@ pid_t __vfork(jmp_buf env) parent_leavepretendchild(udata); - /* save child id before freeing udata */ - child_id = udata->child_id; + /* Save some data from udata before udata is being freed */ + ULONG child_id = udata->child_id; + jmp_buf env; *env = *udata->vfork_jmp; D(bug("__vfork: Parent: freeing udata\n")); FreeMem(udata, sizeof(struct vfork_data)); - D(bug("__vfork: Parent jumping to jmp_buf %p (child=%d)\n", udata->vfork_jmp, child_id)); - D(bug("__vfork: ip: %p, stack: %p\n", udata->vfork_jmp->retaddr, udata->vfork_jmp->regs[SP])); - vfork_longjmp(udata->vfork_jmp, child_id); + D(bug("__vfork: Parent jumping to jmp_buf %p (child=%d)\n", env, child_id)); + D(bug("__vfork: ip: %p, stack: %p\n", env->retaddr, env->regs[SP])); + vfork_longjmp(env, child_id); assert(0); /* not reached */ return (pid_t) 1; } - - parent_enterpretendchild(udata); - - D(bug("__vfork: Child %d jumping to jmp_buf %p\n", udata->child_id, &udata->vfork_jmp)); - D(bug("__vfork: ip: %p, stack: %p alt: %p\n", udata->vfork_jmp[0].retaddr, udata->vfork_jmp[0].regs[SP], - udata->vfork_jmp[0].regs[ALT])); - - vfork_longjmp(udata->vfork_jmp, 0); - assert(0); /* not reached */ - return (pid_t) 0; } diff --git a/compiler/clib/__vfork.h b/compiler/clib/__vfork.h index f5ad47af07..6969aed98b 100644 --- a/compiler/clib/__vfork.h +++ b/compiler/clib/__vfork.h @@ -21,9 +21,8 @@ struct vfork_data jmp_buf vfork_jmp; struct Task *parent; - jmp_buf arosc_exit_jmp; - - ULONG child_id; + int *parent_olderrorptr; + jmp_buf parent_oldexitjmp, parent_newexitjmp; BYTE parent_signal; struct aroscbase *parent_aroscbase; APTR parent_mempool; @@ -35,12 +34,14 @@ struct vfork_data int parent_numslots; fdesc **parent_fd_array; + ULONG child_id; struct Task *child; struct arosc_privdata *cpriv; int child_executed; - int child_errno; + int child_error, child_errno; BYTE child_signal; struct aroscbase *child_aroscbase; + jmp_buf child_exitjmp; const char *exec_filename; char *const *exec_argv; diff --git a/compiler/clib/_exit.c b/compiler/clib/_exit.c index 5d9e1d7c01..b35c82c5ea 100644 --- a/compiler/clib/_exit.c +++ b/compiler/clib/_exit.c @@ -53,13 +53,7 @@ ******************************************************************************/ { - struct aroscbase *aroscbase = __aros_getbase(); - - *aroscbase->acb_startup_error_ptr = code; - - D(bug("_exit() - returning via jmp_buf %p\n", aroscbase->acb_exit_jmp_buf)); - aroscbase->acb_flags |= ABNORMAL_EXIT; - longjmp (aroscbase->acb_exit_jmp_buf, 1); + __arosc_jmp2exit(0, code); /* never reached */ assert(0); diff --git a/compiler/clib/abort.c b/compiler/clib/abort.c index 640336ab8a..ef3510c84f 100644 --- a/compiler/clib/abort.c +++ b/compiler/clib/abort.c @@ -54,11 +54,8 @@ { raise(SIGABRT); - struct aroscbase *aroscbase = __aros_getbase(); - /* Abort anyway */ - aroscbase->acb_flags |= ABNORMAL_EXIT; - longjmp(aroscbase->acb_exit_jmp_buf, 20); + __arosc_jmp2exit(0, 20); assert(0); /* Should not be reached and will likely bomb recursively */ } diff --git a/compiler/clib/arosc.conf b/compiler/clib/arosc.conf index e0b07e781e..fd59823645 100644 --- a/compiler/clib/arosc.conf +++ b/compiler/clib/arosc.conf @@ -327,4 +327,7 @@ int getrlimit(int resource, struct rlimit *rlp) int setrlimit(int resource, const struct rlimit *rlp) void __arosc_set_environptr(char ***environptr) int __arosc_gmtoffset(void) +int *__arosc_set_errorptr(int *errorptr) +void __arosc_set_exitjmp(jmp_buf exitjmp, jmp_buf previousjmp) +void __arosc_jmp2exit(int normal, int retcode) ##end functionlist diff --git a/compiler/clib/exit.c b/compiler/clib/exit.c index 1fe338d873..a498286505 100644 --- a/compiler/clib/exit.c +++ b/compiler/clib/exit.c @@ -8,9 +8,10 @@ #include "__arosc_privdata.h" #include -#include -#include #include +#include + +#include /***************************************************************************** @@ -58,13 +59,11 @@ ******************************************************************************/ { - struct aroscbase *aroscbase = __aros_getbase(); - D(bug("[arosc] exit(%d)\n", code)); - *aroscbase->acb_startup_error_ptr = code; - longjmp (aroscbase->acb_exit_jmp_buf, 1); + __arosc_jmp2exit(1, code); /* never reached */ + assert(0); } /* exit */ diff --git a/compiler/clib/include/sys/arosc.h b/compiler/clib/include/sys/arosc.h index d253b0e1a7..c55f8dc38e 100644 --- a/compiler/clib/include/sys/arosc.h +++ b/compiler/clib/include/sys/arosc.h @@ -36,6 +36,9 @@ int __arosc_nixmain(int (*main)(int argc, char *argv[]), int argc, char *argv[]) int __get_default_file(int file_descriptor, long* file_handle); void __arosc_program_startup(jmp_buf exitjmp, int *error_ptr); void __arosc_program_end(void); +int *__arosc_set_errorptr(int *errorptr); +void __arosc_set_exitjmp(jmp_buf exitjmp, jmp_buf previousjmp); +void __arosc_jmp2exit(int normal, int returncode) __noreturn; __END_DECLS -- 2.11.4.GIT