1  /* Test if CLONE_VM does not change pthread pid/tid field (BZ #19957)
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <sched.h>
      20  #include <signal.h>
      21  #include <string.h>
      22  #include <stdio.h>
      23  #include <fcntl.h>
      24  #include <unistd.h>
      25  #include <stddef.h>
      26  #include <stdbool.h>
      27  #include <stdint.h>
      28  #include <stdlib.h>
      29  #include <sys/types.h>
      30  #include <sys/wait.h>
      31  #include <sys/syscall.h>
      32  
      33  #include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
      34  
      35  #include <support/check.h>
      36  
      37  static int sig;
      38  static int pipefd[2];
      39  
      40  static int
      41  f (void *a)
      42  {
      43    close (pipefd[0]);
      44  
      45    pid_t ppid = getppid ();
      46    pid_t pid = getpid ();
      47    pid_t tid = syscall (__NR_gettid);
      48  
      49    if (write (pipefd[1], &ppid, sizeof ppid) != sizeof (ppid))
      50      FAIL_EXIT1 ("write ppid failed\n");
      51    if (write (pipefd[1], &pid, sizeof pid) != sizeof (pid))
      52      FAIL_EXIT1 ("write pid failed\n");
      53    if (write (pipefd[1], &tid, sizeof tid) != sizeof (tid))
      54      FAIL_EXIT1 ("write tid failed\n");
      55  
      56    return 0;
      57  }
      58  
      59  
      60  static int
      61  do_test (void)
      62  {
      63    sig = SIGRTMIN;
      64    sigset_t ss;
      65    sigemptyset (&ss);
      66    sigaddset (&ss, sig);
      67    if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
      68      FAIL_EXIT1 ("sigprocmask failed: %m");
      69  
      70    if (pipe2 (pipefd, O_CLOEXEC))
      71      FAIL_EXIT1 ("pipe failed: %m");
      72  
      73    int clone_flags = 0;
      74  #ifdef __ia64__
      75    extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
      76  		       size_t __child_stack_size, int __flags,
      77  		       void *__arg, ...);
      78    char st[256 * 1024] __attribute__ ((aligned));
      79    pid_t p = __clone2 (f, st, sizeof (st), clone_flags, 0);
      80  #else
      81    char st[128 * 1024] __attribute__ ((aligned));
      82  #if _STACK_GROWS_DOWN
      83    pid_t p = clone (f, st + sizeof (st), clone_flags, 0);
      84  #elif _STACK_GROWS_UP
      85    pid_t p = clone (f, st, clone_flags, 0);
      86  #else
      87  #error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
      88  #endif
      89  #endif
      90  
      91    close (pipefd[1]);
      92  
      93    if (p == -1)
      94      FAIL_EXIT1("clone failed: %m");
      95  
      96    pid_t ppid, pid, tid;
      97    if (read (pipefd[0], &ppid, sizeof pid) != sizeof pid)
      98      {
      99        kill (p, SIGKILL);
     100        FAIL_EXIT1 ("read ppid failed: %m");
     101      }
     102    if (read (pipefd[0], &pid, sizeof pid) != sizeof pid)
     103      {
     104        kill (p, SIGKILL);
     105        FAIL_EXIT1 ("read pid failed: %m");
     106      }
     107    if (read (pipefd[0], &tid, sizeof tid) != sizeof tid)
     108      {
     109        kill (p, SIGKILL);
     110        FAIL_EXIT1 ("read tid failed: %m");
     111      }
     112  
     113    close (pipefd[0]);
     114  
     115    int ret = 0;
     116  
     117    pid_t own_pid = getpid ();
     118    pid_t own_tid = syscall (__NR_gettid);
     119  
     120    /* Some sanity checks for clone syscall: returned ppid should be current
     121       pid and both returned tid/pid should be different from current one.  */
     122    if ((ppid != own_pid) || (pid == own_pid) || (tid == own_tid))
     123      FAIL_RET ("ppid=%i pid=%i tid=%i | own_pid=%i own_tid=%i",
     124  	      (int)ppid, (int)pid, (int)tid, (int)own_pid, (int)own_tid);
     125  
     126    int e;
     127    if (waitpid (p, &e, __WCLONE) != p)
     128      {
     129        kill (p, SIGKILL);
     130        FAIL_EXIT1 ("waitpid failed");
     131      }
     132    if (!WIFEXITED (e))
     133      {
     134        if (WIFSIGNALED (e))
     135  	printf ("died from signal %s\n", strsignal (WTERMSIG (e)));
     136        else
     137  	puts ("did not terminate correctly");
     138        exit (EXIT_FAILURE);
     139      }
     140    if (WEXITSTATUS (e) != 0)
     141      FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e));
     142  
     143    return ret;
     144  }
     145  
     146  #include <support/test-driver.c>