Blame nptl/tst-stack4.c

Packit 6c4009
/* Test DTV size oveflow when pthread_create reuses old DTV and TLS is
Packit 6c4009
   used by dlopened shared object.
Packit 6c4009
   Copyright (C) 2014-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 <stdio.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <pthread.h>
Packit 6c4009
Packit 6c4009
/* The choices of thread count, and file counts are arbitary.
Packit 6c4009
   The point is simply to run enough threads that an exiting
Packit 6c4009
   thread has it's stack reused by another thread at the same
Packit 6c4009
   time as new libraries have been loaded.  */
Packit 6c4009
#define DSO_SHARED_FILES 20
Packit 6c4009
#define DSO_OPEN_THREADS 20
Packit 6c4009
#define DSO_EXEC_THREADS 2
Packit 6c4009
Packit 6c4009
/* Used to make sure that only one thread is calling dlopen and dlclose
Packit 6c4009
   at a time.  */
Packit 6c4009
pthread_mutex_t g_lock;
Packit 6c4009
Packit 6c4009
typedef void (*function) (void);
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
dso_invoke(void *dso_fun)
Packit 6c4009
{
Packit 6c4009
  function *fun_vec = (function *) dso_fun;
Packit 6c4009
  int dso;
Packit 6c4009
Packit 6c4009
  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
Packit 6c4009
    (*fun_vec[dso]) ();
Packit 6c4009
Packit 6c4009
  pthread_exit (NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
dso_process (void * p)
Packit 6c4009
{
Packit 6c4009
  void *handle[DSO_SHARED_FILES];
Packit 6c4009
  function fun_vec[DSO_SHARED_FILES];
Packit 6c4009
  char dso_path[DSO_SHARED_FILES][100];
Packit 6c4009
  int dso;
Packit 6c4009
  int t = (int) (uintptr_t) p;
Packit 6c4009
Packit 6c4009
  /* Open DSOs and get a function.  */
Packit 6c4009
  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
Packit 6c4009
    {
Packit 6c4009
      sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso);
Packit 6c4009
Packit 6c4009
      pthread_mutex_lock (&g_lock);
Packit 6c4009
Packit 6c4009
      handle[dso] = dlopen (dso_path[dso], RTLD_NOW);
Packit 6c4009
      assert (handle[dso]);
Packit 6c4009
Packit 6c4009
      fun_vec[dso] = (function) dlsym (handle[dso], "function");
Packit 6c4009
      assert (fun_vec[dso]);
Packit 6c4009
Packit 6c4009
      pthread_mutex_unlock (&g_lock);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Spawn workers.  */
Packit 6c4009
  pthread_t thread[DSO_EXEC_THREADS];
Packit 6c4009
  int i, ret;
Packit 6c4009
  uintptr_t result = 0;
Packit 6c4009
  for (i = 0; i < DSO_EXEC_THREADS; i++)
Packit 6c4009
    {
Packit 6c4009
      pthread_mutex_lock (&g_lock);
Packit 6c4009
      ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec);
Packit 6c4009
      if (ret != 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("pthread_create failed: %d\n", ret);
Packit 6c4009
	  result = 1;
Packit 6c4009
	}
Packit 6c4009
      pthread_mutex_unlock (&g_lock);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (!result)
Packit 6c4009
    for (i = 0; i < DSO_EXEC_THREADS; i++)
Packit 6c4009
      {
Packit 6c4009
	ret = pthread_join (thread[i], NULL);
Packit 6c4009
	if (ret != 0)
Packit 6c4009
	  {
Packit 6c4009
	    printf ("pthread_join failed: %d\n", ret);
Packit 6c4009
	    result = 1;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  /* Close all DSOs.  */
Packit 6c4009
  for (dso = 0; dso < DSO_SHARED_FILES; dso++)
Packit 6c4009
    {
Packit 6c4009
      pthread_mutex_lock (&g_lock);
Packit 6c4009
      dlclose (handle[dso]);
Packit 6c4009
      pthread_mutex_unlock (&g_lock);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Exit.  */
Packit 6c4009
  pthread_exit ((void *) result);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  pthread_t thread[DSO_OPEN_THREADS];
Packit 6c4009
  int i,j;
Packit 6c4009
  int ret;
Packit 6c4009
  int result = 0;
Packit 6c4009
Packit 6c4009
  pthread_mutex_init (&g_lock, NULL);
Packit 6c4009
Packit 6c4009
  /* 100 is arbitrary here and is known to trigger PR 13862.  */
Packit 6c4009
  for (j = 0; j < 100; j++)
Packit 6c4009
    {
Packit 6c4009
      for (i = 0; i < DSO_OPEN_THREADS; i++)
Packit 6c4009
	{
Packit 6c4009
	  ret = pthread_create (&thread[i], NULL, dso_process,
Packit 6c4009
				(void *) (uintptr_t) i);
Packit 6c4009
	  if (ret != 0)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("pthread_create failed: %d\n", ret);
Packit 6c4009
	      result = 1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (result)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      for (i = 0; i < DSO_OPEN_THREADS; i++)
Packit 6c4009
	{
Packit 6c4009
	  ret = pthread_join (thread[i], NULL);
Packit 6c4009
	  if (ret != 0)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("pthread_join failed: %d\n", ret);
Packit 6c4009
	      result = 1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#define TIMEOUT 100
Packit 6c4009
#include "../test-skeleton.c"