summaryrefslogtreecommitdiff
path: root/test/setjmp/tst-vfork-longjmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/setjmp/tst-vfork-longjmp.c')
-rw-r--r--test/setjmp/tst-vfork-longjmp.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/test/setjmp/tst-vfork-longjmp.c b/test/setjmp/tst-vfork-longjmp.c
new file mode 100644
index 0000000..2784424
--- /dev/null
+++ b/test/setjmp/tst-vfork-longjmp.c
@@ -0,0 +1,108 @@
+/* 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;
+
+static 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;
+
+static 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 max;
+ /* values modified between setjmp/longjmp cannot be local to this func */
+ static int cnt, 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()/exec() inside 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()/sigprocmask() 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;
+}