(root)/
strace-6.5/
tests/
clone-flags.c
       1  /*
       2   * Check decoding of clone flags.
       3   *
       4   * Copyright (c) 2017-2021 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include "xmalloc.h"
      12  
      13  #include <errno.h>
      14  #include <limits.h>
      15  #include <sched.h>
      16  #include <signal.h>
      17  #include <stdio.h>
      18  #include <stdlib.h>
      19  #include <sys/wait.h>
      20  #include <unistd.h>
      21  #include <linux/sched.h>
      22  
      23  static const int child_exit_status = 42;
      24  static pid_t pid;
      25  
      26  static pid_t
      27  wait_cloned(pid_t pid, int sig, const char *text)
      28  {
      29  	if (pid < 0)
      30  		perror_msg_and_fail("clone %s", text);
      31  	int status;
      32  	pid_t rc = wait(&status);
      33  	if (sig) {
      34  		if (rc != pid)
      35  			perror_msg_and_fail("unexpected wait rc %d from %s",
      36  					    rc, text);
      37  		if (!WIFEXITED(status) ||
      38  		    WEXITSTATUS(status) != child_exit_status)
      39  			error_msg_and_fail("unexpected wait status %#x from %s",
      40  					   status, text);
      41  	} else {
      42  		if (rc >= 0)
      43  			error_msg_and_fail("unexpected wait rc %d from %s",
      44  					   rc, text);
      45  	}
      46  	return pid;
      47  }
      48  
      49  #ifdef IA64
      50  extern int __clone2(int (*)(void *), void *, size_t, int, void *, ...);
      51  # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
      52  	wait_cloned(__clone2((fn_), (stack_), (size_), (flags_), (arg_), \
      53  			     ## __VA_ARGS__), (flags_) & 0xff, #flags_)
      54  # define SYSCALL_NAME "clone2"
      55  # define STACK_SIZE_FMT ", stack_size=%#lx"
      56  # define STACK_SIZE_ARG child_stack_size,
      57  #else
      58  # define do_clone(fn_, stack_, size_, flags_, arg_, ...) \
      59  	wait_cloned(clone((fn_), (stack_), (flags_), (arg_),	\
      60  			  ## __VA_ARGS__), (flags_) & 0xff, #flags_)
      61  # define SYSCALL_NAME "clone"
      62  # define STACK_SIZE_FMT ""
      63  # define STACK_SIZE_ARG
      64  #endif
      65  
      66  static int
      67  child(void *const arg)
      68  {
      69  	return child_exit_status;
      70  }
      71  
      72  int
      73  main(void)
      74  {
      75  	const unsigned long child_stack_size = get_page_size();
      76  	void *const child_stack =
      77  		tail_alloc(child_stack_size * 2) + child_stack_size;
      78  
      79  	const char *child_stack_expected_str = getenv("CHILD_STACK_EXPECTED");
      80  	const char *child_stack_reported_str = getenv("CHILD_STACK_REPORTED");
      81  
      82  	if (!child_stack_expected_str || !child_stack_reported_str) {
      83  		const unsigned long child_stack_base =
      84  			(unsigned long) child_stack / 0x1000;
      85  		pid = do_clone(child, child_stack, child_stack_size,
      86  			       SIGCHLD, 0);
      87  		printf("%s\\(child_stack=(%#lx|%#lx)[[:xdigit:]]{3}"
      88  		       STACK_SIZE_FMT ", flags=%s\\) = %d\n",
      89  		       SYSCALL_NAME, child_stack_base, child_stack_base - 1,
      90  		       STACK_SIZE_ARG "SIGCHLD", pid);
      91  		return 0;
      92  	}
      93  	const unsigned long child_stack_expected =
      94  		strtoul(child_stack_expected_str, 0, 16);
      95  	const unsigned long child_stack_reported =
      96  		strtoul(child_stack_reported_str, 0, 16);
      97  	const unsigned long child_stack_printed =
      98  		(unsigned long) child_stack +
      99  		(child_stack_reported - child_stack_expected);
     100  
     101  	pid = do_clone(child, child_stack, child_stack_size, 0, 0);
     102  	printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
     103  	       SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
     104  	       "0", pid);
     105  
     106  	pid = do_clone(child, child_stack, child_stack_size, CLONE_FS, 0);
     107  	printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
     108  	       SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
     109  	       "CLONE_FS", pid);
     110  
     111  	pid = do_clone(child, child_stack, child_stack_size, SIGCHLD, 0);
     112  	printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
     113  	       SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
     114  	       "SIGCHLD", pid);
     115  
     116  	pid = do_clone(child, child_stack, child_stack_size,
     117  		       CLONE_FS|SIGCHLD, 0);
     118  	printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s) = %d\n",
     119  	       SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
     120  	       "CLONE_FS|SIGCHLD", pid);
     121  
     122  	TAIL_ALLOC_OBJECT_CONST_PTR(pid_t, ptid);
     123  	pid = do_clone(child, child_stack, child_stack_size,
     124  		       CLONE_PARENT_SETTID|SIGCHLD, 0, ptid);
     125  	printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s"
     126  	       ", parent_tid=[%u]) = %d\n",
     127  	       SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
     128  	       "CLONE_PARENT_SETTID|SIGCHLD", *ptid, pid);
     129  
     130  	char buf[PATH_MAX];
     131  	if (readlink("/proc/self/fd/0", buf, sizeof(buf) - 1) > 0) {
     132  		*ptid = 0;
     133  		pid = do_clone(child, child_stack, child_stack_size,
     134  			       CLONE_PIDFD|SIGCHLD, 0, ptid);
     135  		char *fname = xasprintf("/proc/self/fd/%d", *ptid);
     136  		int rc = readlink(fname, buf, sizeof(buf) - 1);
     137  		if ((unsigned int) rc >= sizeof(buf))
     138  			perror_msg_and_fail("readlink");
     139  		buf[rc] = '\0';
     140  		printf("%s(child_stack=%#lx" STACK_SIZE_FMT ", flags=%s"
     141  		       ", parent_tid=[%u<%s>]) = %d\n",
     142  		       SYSCALL_NAME, child_stack_printed, STACK_SIZE_ARG
     143  		       "CLONE_PIDFD|SIGCHLD", *ptid, buf, pid);
     144  	}
     145  
     146  	return 0;
     147  }