I'm a TA for an operating systems class where the students are tasked with developing a fork bomb defuser. As part of the test cases I wanted to develop something that looked like a fork bomb, but was in fact fairly safe (i.e. spawns off many processes, but those processes are removed). My question is that on testing this on my OS X machine I noticed that it actually kills all my user processes if I set the usleep delay too low(~100000) and the number of children too high(~1000). When I say all I mean Firefox, Xcode, Word, even Finder seems to go down. This seems somewhat strange to me, as the task only ever has one child, but I am wondering if OS X has a limit to the number of child processes a user can have. I wasn't able to find anything on google, but any suggestions are appreciated.
In particular: 1) Is this code unreasonable and I'm missing some obvious reason it should be killed? 2) Is there some documentation in OS X that might explain the reason we are seeing this behavior?
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
pid_t pid;
if(argc < 2) {
printf("Usage: fork_safe n\n");
return 0;
}
int n = strtol(argv[1], NULL, 10);
for(i = 0; i < n; i++) {
pid = fork();
if(pid == 0){
break;
} else {
printf("child pid %d, killing...\n", pid);
usleep(10000);
kill(pid,SIGTERM);
fflush(stdout);
}
}
while(1);
return 0;
}
You are not checking the return value from fork()
for error. And if it returns -1
, you're passing -1 into the kill
function.
And according to the man page for the kill function:
If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below.
So I suspect that fork
fails when it can't allocate any more processes. Thereby, your code is sending a SIGTERM to EVERY process your account owns. That explains the behavior you are seeing.
Modify your for-loop accordingly:
for(i = 0; i < n; i++)
{
pid = fork();
if(pid == 0)
{
break;
}
else if (pid == -1)
{
printf("Unable to allocate any more processes\n");
return 0;
}
else
{
printf("child pid %d, killing...\n", pid);
usleep(10000);
kill(pid,SIGTERM);
fflush(stdout);
}
}