diff options
Diffstat (limited to 'stdlib/tst-setcontext3.c')
-rw-r--r-- | stdlib/tst-setcontext3.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/stdlib/tst-setcontext3.c b/stdlib/tst-setcontext3.c new file mode 100644 index 0000000000..fda21285c6 --- /dev/null +++ b/stdlib/tst-setcontext3.c @@ -0,0 +1,138 @@ +/* Bug 18125: Verify setcontext calls exit() and not _exit(). + Copyright (C) 2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> +#include <unistd.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +/* Please note that depending on the outcome of Bug 18135 this test + may become invalid, and instead of testing for calling exit it + should be reworked to test for the last context calling + pthread_exit(). */ + +static ucontext_t ctx; +static char *filename; + +/* It is intended that this function does nothing. */ +static void +cf (void) +{ + printf ("called context function\n"); +} + +static void +exit_called (void) +{ + int fd; + ssize_t res; + const char buf[] = "Called exit function\n"; + + fd = open (filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd == -1) + { + printf ("FAIL: Unable to create test file %s\n", filename); + exit (1); + } + res = write (fd, buf, sizeof (buf)); + if (res != sizeof (buf)) + { + printf ("FAIL: Expected to write test file in one write call.\n"); + exit (1); + } + res = close (fd); + if (res == -1) + { + printf ("FAIL: Failed to close test file.\n"); + exit (1); + } + printf ("PASS: %s", buf); +} + +/* The test expects a filename given by the wrapper calling script. + The test then registers an atexit handler that will create the + file to indicate that the atexit handler ran. Then the test + creates a context, modifies it with makecontext, and sets it. + The context has only a single context which then must exit. + If it incorrectly exits via _exit then the atexit handler is + not run, the file is not created, and the wrapper detects this + and fails the test. This test cannot be done using an _exit + interposer since setcontext avoids the PLT and calls _exit + directly. */ +static int +do_test (int argc, char **argv) +{ + int ret; + char st1[32768]; + ucontext_t tempctx = ctx; + + if (argc < 2) + { + printf ("FAIL: Test missing filename argument.\n"); + exit (1); + } + + filename = argv[1]; + + atexit (exit_called); + + puts ("making contexts"); + if (getcontext (&ctx) != 0) + { + if (errno == ENOSYS) + { + /* Exit with 77 to mark the test as UNSUPPORTED. */ + printf ("UNSUPPORTED: getcontext not implemented.\n"); + exit (77); + } + + printf ("FAIL: getcontext failed.\n"); + exit (1); + } + + ctx.uc_stack.ss_sp = st1; + ctx.uc_stack.ss_size = sizeof (st1); + ctx.uc_link = 0; + makecontext (&ctx, cf, 0); + + /* Without this check, a stub makecontext can make us spin forever. */ + if (memcmp (&tempctx, &ctx, sizeof ctx) == 0) + { + puts ("UNSUPPORTED: makecontext was a no-op, presuming not implemented"); + exit (77); + } + + ret = setcontext (&ctx); + if (ret != 0) + { + printf ("FAIL: setcontext returned with %d and errno of %d.\n", ret, errno); + exit (1); + } + + printf ("FAIL: Impossibly returned to main.\n"); + exit (1); +} + +#include "../test-skeleton.c" |