Blame malloc/tst-malloc-stats-cancellation.c

Packit Service 82fcde
/* Bug 22830: malloc_stats fails to re-enable cancellation on exit.
Packit Service 82fcde
   Copyright (C) 2018 Free Software Foundation.
Packit Service 82fcde
   Copying and distribution of this file, with or without modification,
Packit Service 82fcde
   are permitted in any medium without royalty provided the copyright
Packit Service 82fcde
   notice and this notice are preserved. This file is offered as-is,
Packit Service 82fcde
   without any warranty.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
Packit Service 82fcde
#include <pthread.h>
Packit Service 82fcde
#include <sys/stat.h>
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
#include <fcntl.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
Packit Service 82fcde
#include <malloc.h>
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
test_threadproc (void *gatep)
Packit Service 82fcde
{
Packit Service 82fcde
  /* When we are released from the barrier, there is a cancellation
Packit Service 82fcde
     request pending for this thread.  N.B. pthread_barrier_wait is
Packit Service 82fcde
     not itself a cancellation point (oddly enough).  */
Packit Service 82fcde
  pthread_barrier_wait ((pthread_barrier_t *)gatep);
Packit Service 82fcde
  malloc_stats ();
Packit Service 82fcde
  fputs ("this call should trigger cancellation\n", stderr);
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* We cannot replace stderr with a memstream because writes to memstreams
Packit Service 82fcde
   do not trigger cancellation.  Instead, main swaps out fd 2 to point to
Packit Service 82fcde
   a pipe, and this thread reads from the pipe and writes to a memstream
Packit Service 82fcde
   until EOF, then returns the data accumulated in the memstream.  main
Packit Service 82fcde
   can't do that itself because, when the test thread gets cancelled,
Packit Service 82fcde
   it doesn't close the pipe.  */
Packit Service 82fcde
Packit Service 82fcde
struct buffer_tp_args
Packit Service 82fcde
{
Packit Service 82fcde
  int ifd;
Packit Service 82fcde
  FILE *real_stderr;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
buffer_threadproc (void *argp)
Packit Service 82fcde
{
Packit Service 82fcde
  struct buffer_tp_args *args = argp;
Packit Service 82fcde
  int ifd = args->ifd;
Packit Service 82fcde
  char block[BUFSIZ], *p;
Packit Service 82fcde
  ssize_t nread;
Packit Service 82fcde
  size_t nwritten;
Packit Service 82fcde
Packit Service 82fcde
  char *obuf = 0;
Packit Service 82fcde
  size_t obufsz = 0;
Packit Service 82fcde
  FILE *ofp = open_memstream (&obuf, &obufsz);
Packit Service 82fcde
  if (!ofp)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (args->real_stderr,
Packit Service 82fcde
               "buffer_threadproc: open_memstream: %s\n", strerror (errno));
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  while ((nread = read (ifd, block, BUFSIZ)) > 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      p = block;
Packit Service 82fcde
      do
Packit Service 82fcde
        {
Packit Service 82fcde
          nwritten = fwrite_unlocked (p, 1, nread, ofp);
Packit Service 82fcde
          if (nwritten == 0)
Packit Service 82fcde
            {
Packit Service 82fcde
              fprintf (args->real_stderr,
Packit Service 82fcde
                       "buffer_threadproc: fwrite_unlocked: %s\n",
Packit Service 82fcde
                       strerror (errno));
Packit Service 82fcde
              return 0;
Packit Service 82fcde
            }
Packit Service 82fcde
          nread -= nwritten;
Packit Service 82fcde
          p += nwritten;
Packit Service 82fcde
        }
Packit Service 82fcde
      while (nread > 0);
Packit Service 82fcde
    }
Packit Service 82fcde
  if (nread == -1)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (args->real_stderr, "buffer_threadproc: read: %s\n",
Packit Service 82fcde
               strerror (errno));
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  close (ifd);
Packit Service 82fcde
  fclose (ofp);
Packit Service 82fcde
  return obuf;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
main (void)
Packit Service 82fcde
{
Packit Service 82fcde
  int result = 0, err, real_stderr_fd, bufpipe[2];
Packit Service 82fcde
  pthread_t t_thr, b_thr;
Packit Service 82fcde
  pthread_barrier_t gate;
Packit Service 82fcde
  void *rv;
Packit Service 82fcde
  FILE *real_stderr;
Packit Service 82fcde
  char *obuf;
Packit Service 82fcde
  void *obuf_v;
Packit Service 82fcde
  struct buffer_tp_args b_args;
Packit Service 82fcde
Packit Service 82fcde
  real_stderr_fd = dup (2);
Packit Service 82fcde
  if (real_stderr_fd == -1)
Packit Service 82fcde
    {
Packit Service 82fcde
      perror ("dup");
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
  real_stderr = fdopen(real_stderr_fd, "w");
Packit Service 82fcde
  if (!real_stderr)
Packit Service 82fcde
    {
Packit Service 82fcde
      perror ("fdopen");
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (setvbuf (real_stderr, 0, _IOLBF, 0))
Packit Service 82fcde
    {
Packit Service 82fcde
      perror ("setvbuf(real_stderr)");
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pipe (bufpipe))
Packit Service 82fcde
    {
Packit Service 82fcde
      perror ("pipe");
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Below this point, nobody other than the test_threadproc should use
Packit Service 82fcde
     the normal stderr.  */
Packit Service 82fcde
  if (dup2 (bufpipe[1], 2) == -1)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "dup2: %s\n", strerror (errno));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
  close (bufpipe[1]);
Packit Service 82fcde
Packit Service 82fcde
  b_args.ifd = bufpipe[0];
Packit Service 82fcde
  b_args.real_stderr = real_stderr;
Packit Service 82fcde
  err = pthread_create (&b_thr, 0, buffer_threadproc, &b_args);
Packit Service 82fcde
  if (err)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "pthread_create(buffer_thr): %s\n",
Packit Service 82fcde
               strerror (err));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  err = pthread_barrier_init (&gate, 0, 2);
Packit Service 82fcde
  if (err)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "pthread_barrier_init: %s\n", strerror (err));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  err = pthread_create (&t_thr, 0, test_threadproc, &gate);
Packit Service 82fcde
  if (err)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "pthread_create(test_thr): %s\n", strerror (err));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  err = pthread_cancel (t_thr);
Packit Service 82fcde
  if (err)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "pthread_cancel: %s\n", strerror (err));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_barrier_wait (&gate); /* cannot fail */
Packit Service 82fcde
Packit Service 82fcde
  err = pthread_join (t_thr, &rv;;
Packit Service 82fcde
  if (err)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "pthread_join(test_thr): %s\n", strerror (err));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Closing the normal stderr releases the buffer_threadproc from its
Packit Service 82fcde
     loop.  */
Packit Service 82fcde
  fclose (stderr);
Packit Service 82fcde
  err = pthread_join (b_thr, &obuf_v);
Packit Service 82fcde
  if (err)
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (real_stderr, "pthread_join(buffer_thr): %s\n", strerror (err));
Packit Service 82fcde
      return 2;
Packit Service 82fcde
    }
Packit Service 82fcde
  obuf = obuf_v;
Packit Service 82fcde
  if (obuf == 0)
Packit Service 82fcde
    return 2; /* error within buffer_threadproc, already reported */
Packit Service 82fcde
Packit Service 82fcde
  if (rv != PTHREAD_CANCELED)
Packit Service 82fcde
    {
Packit Service 82fcde
      fputs ("FAIL: thread was not cancelled\n", real_stderr);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  /* obuf should have received all of the text printed by malloc_stats,
Packit Service 82fcde
     but not the text printed by the final call to fputs.  */
Packit Service 82fcde
  if (!strstr (obuf, "max mmap bytes"))
Packit Service 82fcde
    {
Packit Service 82fcde
      fputs ("FAIL: malloc_stats output incomplete\n", real_stderr);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (strstr (obuf, "this call should trigger cancellation"))
Packit Service 82fcde
    {
Packit Service 82fcde
      fputs ("FAIL: fputs produced output\n", real_stderr);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (result == 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      fputs ("--- output from thread below ---\n", real_stderr);
Packit Service 82fcde
      fputs (obuf, real_stderr);
Packit Service 82fcde
    }
Packit Service 82fcde
  return result;
Packit Service 82fcde
}