Earlier quoted context omitted.
What's wrong with the C version? char *dir = "/foo"; mkdir(dir, 0700); if (chdir(dir) == 0) delete_all_files();
That's incomplete in that it doesn't automatically chdir back. A proper block-scope "with-" macro will wrap the body in something like: char *olddir = getcwd(); chdir(newdir); try { do_stuff(); } finally { chdir(olddir); }
fork() can fail
231–240 of 320 posts
Re: fork() can fail
#232Earlier quoted context omitted.
That's incomplete in that it doesn't automatically chdir back. A proper block-scope "with-" macro will wrap the body in something like: char *olddir = getcwd(); chdir(newdir); try { do_stuff(); } finally { chdir(olddir); }
'try' and 'finally' are in C now? Someone should warn the GCC guys they're behind the times. Also, getcwd has a size parameter these days, and of course you want to check if the getcwd actually worked.
Re: fork() can fail
#233When I was young and really didn't understand Unix, my friend and were summer students at NBS (now NIST), and one fine afternoon we wondered what would happen if you ran fork() forever. We didn't know, so we wrote the program and ran it. This was on a PDP-11/45 running v6 or v7 Unix. The printing console (some DECWriter 133 something or other) started burping and spewing stuff about fork failing and other bad things,…
> ...a minute or two later one of the folks who had 'root' ran into the machine room with a panic-stricken look because the system had mostly just locked up. It's kind of weird that, while root has always had e.g. 5% reserved disk space on the rootfs for emergencies, one thing no Unix has ever done is enforce a 5% CPU reservation for root so administrators can "talk over" a cascading failure. I think this is possible…
Re: fork() can fail
#234Earlier quoted context omitted.
Indeed. I like using a VERIFY macro: #ifdef NDEBUG # define VERIFY(x) ((x), 1) #else # define VERIFY(x) assert((x)) #endif Then you can write VERIFY(pthread_mutex_unlock(&lock) == 0); You don't need, however, to consider the possibility of your program continuing to run after pthread_mutex_unlock fails.
Huh? You do realize that the standard assert() macro already is compiled out if NDEBUG is defined, right? Your code could just as well be written as assert(pthread_mutex_unlock(&lock) == 0); which of course has the added benefit of not inventing anything new, i.e. being standard and immediately understood by anyone who knows the language and its libraries reasonably well.
Re: fork() can fail
#235Earlier quoted context omitted.
Indeed. I like using a VERIFY macro: #ifdef NDEBUG # define VERIFY(x) ((x), 1) #else # define VERIFY(x) assert((x)) #endif Then you can write VERIFY(pthread_mutex_unlock(&lock) == 0); You don't need, however, to consider the possibility of your program continuing to run after pthread_mutex_unlock fails.
Huh? You do realize that the standard assert() macro already is compiled out if NDEBUG is defined, right? Your code could just as well be written as assert(pthread_mutex_unlock(&lock) == 0); which of course has the added benefit of not inventing anything new, i.e. being standard and immediately understood by anyone who knows the language and its libraries reasonably well.
Re: fork() can fail
#236When I was young and really didn't understand Unix, my friend and were summer students at NBS (now NIST), and one fine afternoon we wondered what would happen if you ran fork() forever. We didn't know, so we wrote the program and ran it. This was on a PDP-11/45 running v6 or v7 Unix. The printing console (some DECWriter 133 something or other) started burping and spewing stuff about fork failing and other bad things,…
> ...a minute or two later one of the folks who had 'root' ran into the machine room with a panic-stricken look because the system had mostly just locked up. It's kind of weird that, while root has always had e.g. 5% reserved disk space on the rootfs for emergencies, one thing no Unix has ever done is enforce a 5% CPU reservation for root so administrators can "talk over" a cascading failure. I think this is possible…
Totally limiting the CPU utilization of a group of processes requires more overhead than changing the scheduling priority since you must actively account for the CPU usage. CPU cgroups should do just that though and in most cases the overhead should be acceptable.
In your comment's parent, I don't think raw CPU utilization was the issue since kabdib mentioned fork and it was in response to a post about fork failures. The problems caused by a fork bomb are not limited to CPU utilization, see: https://en.wikipedia.org/wiki/Fork_bomb
In any case, there will likely always be some system call you can abuse to totally exhaust some resource of the kernel.
Re: fork() can fail
#237Earlier quoted context omitted.
Indeed. I like using a VERIFY macro: #ifdef NDEBUG # define VERIFY(x) ((x), 1) #else # define VERIFY(x) assert((x)) #endif Then you can write VERIFY(pthread_mutex_unlock(&lock) == 0); You don't need, however, to consider the possibility of your program continuing to run after pthread_mutex_unlock fails.
Huh? You do realize that the standard assert() macro already is compiled out if NDEBUG is defined, right? Your code could just as well be written as assert(pthread_mutex_unlock(&lock) == 0); which of course has the added benefit of not inventing anything new, i.e. being standard and immediately understood by anyone who knows the language and its libraries reasonably well.
Re: fork() can fail
#238And this right there is why exceptions are a superior mechanism of announcing errors...
Multiple return would be fine too. pid,err = fork()
Erlang gets away with it because dynamically typed + pattern matching + uses MRV for tagged returns, the second property makes it work.
Re: fork() can fail
#239Earlier quoted context omitted.
Are you sure? And what if $programmer forgets to check what's in err? What would pid contain in that case? I mention this because I guess you quoted a kind of syntax that matches the one from Go. So then I'm guessing that Go would simply ignore the error in this case. However, having a proper exception mechanism, if you don't catch the problem, then it bubbles up, and the program doesn't continue with wrong data (whi…
Yeah, better than returning a tuple, it should return a sum type. Then you would need to deconstruct it, like how people suggest using a switch: match fork() -> | Error(errno) -> ... | Pid(pid) -> ... Or a general "Choice" sum, perhaps using phantom types so int isn't compatible with int . But then all of a sudden, instead of a single word being returned, a tag and possibly variably-sized result has to be returned, a…
Re: fork() can fail
#240Earlier quoted context omitted.
I could argue, however, that in this particular case, it's the user's fault for failing to understand the full and defined behavior of fork() in addition to failing to understand the full and defined behavior of other functions, ...say, kill(). It's just as wrong to feed kill() -1 as it would be to feed it -48585 or "babdkd" (unless that is explicitly your intention). A simple sanity check of if [ "${pid} > "0" ]; is…
Fault is not a rivalrous good. It's the user's fault, and it's the API creator's fault. Is there a reason fork can't be changed to just crash the program on failure? Are situations where a program usefully does something other than crash on fork failure, more or less common than situations where a program fails in the way described in the article?
If you were forking in a high-level language such as Python, failing to fork would raise an exception which would possibly crash the program if left unhandled.
C does not have exceptions so return codes are used to indicate success or failure. This is true for nearly every function, not just fork. If you're not checking for errors in a C program, it's going to break in unexpected ways, and will possibly be vulnerable to exploitation.
fork has 3 possible return values: - 0 for the child process - a positive number for the parent process - a negative number if it failed.
If you look at the man page's "Return Value" section, it is extremely clear, see: http://linux.die.net/man/2/fork
"On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately."