1#!/bin/sh 2 3# 4# Copyright (c) 2016 EMC Corp. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# It seems to be possible for ptrace(PT_ATTACH) to race with the delivery 30# of a signal to the same process. 31 32# "panic: Assertion TD_IS_SLEEPING(td) failed at subr_sleepqueue.c:958". 33# https://people.freebsd.org/~pho/stress/log/ptrace5.txt 34# https://people.freebsd.org/~pho/stress/log/ptrace5-2.txt 35# Fixed by r303426. 36 37. ../default.cfg 38 39dir=/tmp 40odir=`pwd` 41cd $dir 42sed '1,/^EOF/d' < $odir/$0 > $dir/ptrace5.c 43mycc -o ptrace5 -Wall -Wextra -O0 -g ptrace5.c -pthread || exit 1 44rm -f ptrace5.c 45cd $odir 46 47/tmp/ptrace5 48s=$? 49 50rm -rf /tmp/ptrace5 51exit $s 52 53EOF 54#include <sys/param.h> 55#include <sys/ptrace.h> 56#include <sys/stat.h> 57#include <sys/wait.h> 58 59#include <err.h> 60#include <errno.h> 61#include <fcntl.h> 62#include <pthread.h> 63#include <signal.h> 64#include <stdio.h> 65#include <stdlib.h> 66#include <time.h> 67#include <unistd.h> 68 69static pid_t pid; 70static pthread_barrier_t barr; 71static int cont; 72 73#define PARALLEL 4 74#define RUNTIME (5 * 60) 75 76static void 77ahandler(int i __unused) 78{ 79 system("ps -Hl"); 80 fprintf(stderr, "SIGALRM pid %d\n", pid); 81 exit(1); 82} 83 84static void 85handler(int i __unused) 86{ 87} 88 89static void * 90t1(void *data __unused) 91{ 92 int status; 93 94 while (cont == 1) { 95 if (ptrace(PT_ATTACH, pid, 0, 0) == -1) 96 err(1, "ptrace(%d)", pid); 97 98 if (waitpid(pid, &status, 0) == -1) 99 err(1, "waitpid"); 100 else if (!WIFSTOPPED(status)) 101 errx(1, "failed to stop child"); 102 if (ptrace(PT_DETACH, pid, 0, 0) == -1) 103 err(1, "ptrace"); 104 usleep(arc4random() % 200); 105 } 106 107 return (NULL); 108} 109 110static void * 111t2(void *data __unused) 112{ 113 while (cont == 1) { 114 if (kill(pid, SIGHUP) == -1) 115 err(1, "kill"); 116 usleep(arc4random() % 200); 117 } 118 119 return (NULL); 120} 121 122static void 123test(void) 124{ 125 pthread_t tid[2]; 126 struct sigaction sa; 127 int r, status; 128 129 r = pthread_barrier_wait(&barr); 130 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) 131 errc(1, r, "pthread_barrier_wait"); 132 133 sa.sa_handler = ahandler; 134 sigemptyset(&sa.sa_mask); 135 sa.sa_flags = 0; 136 if (sigaction(SIGALRM, &sa, NULL) == -1) 137 err(1, "sigaction"); 138 alarm(2 * RUNTIME); 139 sa.sa_handler = handler; 140 sigemptyset(&sa.sa_mask); 141 sa.sa_flags = 0; 142 if (sigaction(SIGHUP, &sa, NULL) == -1) 143 err(1, "sigaction"); 144 145 if ((pid = fork()) == 0) { 146 for(;;) 147 usleep(20); 148 149 _exit(0); 150 } 151 152 cont = 1; 153 if ((r = pthread_create(&tid[0], NULL, t1, NULL)) == -1) 154 errc(1, r, "pthread_create"); 155 if ((r = pthread_create(&tid[1], NULL, t2, NULL)) == -1) 156 errc(1, r, "pthread_create"); 157 158 sleep(RUNTIME); 159 160 cont = 0; 161 if ((r = pthread_join(tid[0], NULL)) == -1) 162 errc(1, r, "pthread_join"); 163 if ((r = pthread_join(tid[1], NULL)) == -1) 164 errc(1, r, "pthread_join"); 165 if (kill(pid, SIGKILL) != 0) 166 err(1, "kill(%d)", pid); 167 waitpid(pid, &status, 0); 168 169 exit(0); 170} 171 172int 173main(void) 174{ 175 pthread_barrierattr_t attr; 176 int e, i, pids[PARALLEL], r, status; 177 178 if ((r = pthread_barrierattr_init(&attr)) != 0) 179 errc(1, r, "pthread_barrierattr_init"); 180 if ((r = pthread_barrierattr_setpshared(&attr, 181 PTHREAD_PROCESS_SHARED)) != 0) 182 errc(1, r, "pthread_barrierattr_setpshared"); 183 if ((r = pthread_barrier_init(&barr, &attr, PARALLEL)) != 0) 184 errc(1, r, "pthread_barrier_init"); 185 186 e = 0; 187 for (i = 0; i < PARALLEL; i++) { 188 if ((pids[i] = fork()) == 0) 189 test(); 190 } 191 for (i = 0; i < PARALLEL; i++) { 192 waitpid(pids[i], &status, 0); 193 e += status == 0 ? 0 : 1; 194 } 195 196 if ((r = pthread_barrier_destroy(&barr)) > 0) 197 errc(1, r, "pthread_barrier_destroy"); 198 199 return (e); 200} 201