1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5# 6# Copyright (c) 2022 Peter Holm <pho@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# Demonstrate lingering child process after a timeout(1) timeout 31# Test scenario suggestions by kib 32 33# Fixed by: 709783373e57 - main - Fix another race between fork(2) and 34# PROC_REAP_KILL subtree 35 36eval prog=reaper.$$ 37cat > /tmp/$prog.c <<EOF 38#include <sys/wait.h> 39#include <err.h> 40#include <signal.h> 41#include <stdlib.h> 42#include <unistd.h> 43 44#define MAXP 10000 45 46int 47main(void) 48{ 49 pid_t pids[MAXP]; 50 int i, parallel; 51 char *cmdline[] = { "SLP", "86400", NULL }; 52 53 for (;;) { 54 parallel = arc4random() % MAXP + 1; 55 for (i = 0; i < parallel; i++) { 56 if ((pids[i] = fork()) == 0) { 57 setproctitle("child"); 58 if ((arc4random() % 100) < 10) { 59 if (execve(cmdline[0], cmdline, 60 NULL) == -1) 61 err(1, "execve"); 62 } else { 63 for (;;) 64 pause(); 65 } 66 _exit(0); /* never reached */ 67 } 68 if (pids[i] == -1) 69 err(1, "fork()"); 70 } 71 72 usleep(arc4random() % 500); 73 74 for (i = 0; i < parallel; i++) { 75 if (kill(pids[i], SIGINT) == -1) 76 err(1, "kill(%d)", pids[i]); 77 if (waitpid(pids[i], NULL, 0) != pids[i]) 78 err(1, "waitpid(%d)", pids[i]); 79 } 80 } 81} 82EOF 83sed -i '' "s#SLP#/tmp/$prog.sleep#" /tmp/$prog.c 84cc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1 85rm /tmp/$prog.c 86 87cp /bin/sleep /tmp/$prog.sleep 88n=1 89start=`date +%s` 90while true; do 91 timeout 2s /tmp/$prog 92 for i in `jot 50`; do 93 pgrep -q $prog || break 94 sleep .5 95 done 96 if pgrep -q $prog; then 97 e=$((`date +%s` - start)) 98 echo "Failed in loop #$n after $e seconds." 99 pgrep "$prog|timeout" | xargs ps -lp 100 pkill $prog 101 rm -f /tmp/$prog /tmp/$prog.sleep 102 exit 1 103 fi 104 [ $((`date +%s` - start)) -ge 600 ] && break 105 n=$((n + 1)) 106done 107rm /tmp/$prog /tmp/$prog.sleep 108exit 0 109