Blame stdlib/tst-setcontext3.c

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