diff options
Diffstat (limited to 'test/setjmp/tst-vfork-longjmp.c')
-rw-r--r-- | test/setjmp/tst-vfork-longjmp.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/test/setjmp/tst-vfork-longjmp.c b/test/setjmp/tst-vfork-longjmp.c new file mode 100644 index 000000000..644379245 --- /dev/null +++ b/test/setjmp/tst-vfork-longjmp.c @@ -0,0 +1,106 @@ +/* make sure we can vfork/exec across setjmp/longjmp's + * and make sure signal block masks don't get corrupted + * in the process. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <unistd.h> +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <string.h> + +int verbose = 0; + +int execute_child(const char *prog) +{ + int status; + pid_t child; + child = vfork(); + if (child == 0) { + execlp(prog, prog, NULL); + perror("Could not execute specified prog"); + _exit(1); + } else if (child == 1) + return 1; + wait(&status); + return WEXITSTATUS(status); +} + +sigset_t orig_mask; + +int check_sig_mask(void) +{ + int status; + pid_t child; + + child = vfork(); + if (child == 0) { + int ret; + sigset_t child_mask; + memset(&child_mask, 0x00, sizeof(child_mask)); + ret = sigprocmask(SIG_BLOCK, NULL, &child_mask); + if (ret != 0) { + perror("could not get child sig block mask"); + _exit(1); + } + ret = memcmp(&orig_mask, &child_mask, sizeof(orig_mask)); + if (verbose) { + printf("sigmsk: %08lx%08lx ", child_mask.__val[1], child_mask.__val[0]); + printf("sigmsk: %08lx%08lx ", orig_mask.__val[1], orig_mask.__val[0]); + printf("%i\n", ret); + } + _exit(ret); + } else if (child == 1) + return 1; + wait(&status); + return WEXITSTATUS(status); +} + +int main(int argc, char *argv[]) +{ + const char *prog; + jmp_buf env; + sigjmp_buf sigenv; + int cnt, max, ret; + + memset(&orig_mask, 0x00, sizeof(orig_mask)); + ret = sigprocmask(SIG_BLOCK, NULL, &orig_mask); + if (ret != 0) { + perror("could not get orig sig block mask"); + return 1; + } + + prog = (argc > 1 ? argv[1] : "true"); + ret = 0; + verbose = 0; + max = 10; + + /* test vfork() instead of sigsetjmp/siglongjmp */ + cnt = 0; + sigsetjmp(sigenv, 1); + ++cnt; + if (verbose) + printf("sigsetjmp loop %i\n", cnt); + ret |= check_sig_mask(); + ret |= execute_child(prog); + if (cnt < max) + siglongjmp(sigenv, 0); + + /* test vfork() inside of setjmp/longjmp */ + cnt = 0; + setjmp(env); + ++cnt; + if (verbose) + printf("setjmp loop %i\n", cnt); + ret |= check_sig_mask(); + ret |= execute_child(prog); + if (cnt < max) + longjmp(env, 0); + + return ret; +} |