xref: /freebsd/tools/test/stress2/misc/ptrace10.sh (revision 4d846d26)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2021 Mark Johnston <markj@FreeBSD.org>
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# ptrace(2) test scenario by Mark Johnston
31# https://people.freebsd.org/~markj/ptrace_stop_mt.c
32# Fixed by r303423.
33
34# stopped on signal 17 after detach
35#  UID   PID  PPID CPU PRI NI  VSZ  RSS MWCHAN STAT TT     TIME COMMAND
36# 1001 47125 62778   0  52  0 6568 2456 wait   S+    2  0:00.01 /bin/sh ./ptrace10.sh
37# 1001 47146 47125   0  23  0 6108 1928 nanslp S+    2  0:00.00 ./ptrace10
38# 1001 47148 47146   0  24  0 6240 1932 -      T+    2  0:00.00 ./ptrace10
39# 1001 47148 47146   0  24  0 6240 1932 -      T+    2  0:00.00 ./ptrace10
40
41. ../default.cfg
42
43cd /tmp
44cat > ptrace10.c <<EOF
45#include <sys/types.h>
46#include <sys/ptrace.h>
47#include <sys/wait.h>
48
49#include <err.h>
50#include <pthread.h>
51#include <signal.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <unistd.h>
55
56static void
57sighup(int sig __unused)
58{
59}
60
61static void
62sleep_forever(void)
63{
64
65	while (1)
66		sleep(1);
67}
68
69static void *
70thread(void *arg __unused)
71{
72
73	sleep_forever();
74	return (NULL);
75}
76
77int
78main(void)
79{
80	struct sigaction act;
81	sigset_t set;
82	pthread_t t;
83	pid_t pid, ret;
84	int e, try, limit, r, status;
85
86	e = 0;
87	pid = fork();
88	if (pid < 0)
89		err(1, "fork");
90	if (pid == 0) {
91		act.sa_handler = sighup;
92		act.sa_flags = 0;
93		sigemptyset(&act.sa_mask);
94		if (sigaction(SIGHUP, &act, NULL) != 0)
95			err(1, "sigaction");
96
97		r = pthread_create(&t, NULL, thread, NULL);
98		if (r != 0)
99			errc(1, r, "pthread_create");
100
101		/* Force SIGHUP to be delivered to the new thread. */
102		sigemptyset(&set);
103		sigaddset(&set, SIGHUP);
104		r = pthread_sigmask(SIG_BLOCK, &set, NULL);
105		if (r != 0)
106			errc(1, r, "pthread_sigmask");
107
108		sleep_forever();
109	} else {
110		sleep(1); /* give the child a chance to set itself up */
111
112		limit = 100;
113		for (try = 1; try <= limit; try++) {
114			if (kill(pid, SIGHUP) != 0)
115				err(1, "kill(SIGHUP)");
116			if (ptrace(PT_ATTACH, pid, NULL, 0) != 0)
117				err(1, "ptrace(PT_ATTACH)");
118			if (waitpid(pid, &status, WUNTRACED) != pid)
119				err(1, "waitpid 1");
120			if (!WIFSTOPPED(status))
121				errx(1, "unexpected status %d after PT_ATTACH",
122				    status);
123			if (ptrace(PT_DETACH, pid, NULL, 0) != 0)
124				err(1, "ptrace(PT_DETACH)");
125
126			sleep(1);
127			ret = waitpid(pid, &status, WUNTRACED | WNOHANG);
128			if (ret < 0)
129				err(1, "waitpid");
130			if (ret == 0)
131				continue;
132			if (!WIFSTOPPED(status))
133				errx(1, "unexpected status %d after PT_DETACH",
134				    status);
135			printf("stopped on signal %d after detach\n",
136			    WSTOPSIG(status));
137			e = 1;
138			break;
139		}
140	}
141	kill(pid, SIGINT);
142
143	return (e);
144}
145EOF
146
147mycc -o ptrace10 -Wall -Wextra -O2 -g ptrace10.c -lpthread || exit 1
148rm ptrace10.c
149
150./ptrace10
151s=$?
152if [ $s -ne 0 ]; then
153	ps -lxH | grep -v grep | egrep "UID|ptrace10"
154	while pgrep -q ptrace10; do
155		pkill -9 ptrace10
156	done
157fi
158wait
159
160rm -f ptrace10
161exit $s
162