Live data from Hacker News

fork() can fail

rachelbythebay.com

221–230 of 320 posts

Re: fork() can fail

#221

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); }

'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

#222
post #20

If a function be advertised to return an error code in the event of difficulties, thou shalt check for that code, yea, even though the checks triple the size of thy code and produce aches in thy typing fingers, for if thou thinkest "it cannot happen to me", the gods shall surely punish thee for thy arrogance. [0] [0]: http://www.lysator.liu.se/c/ten-commandments.html

Counterexample: pthread_mutex_unlock. That function returns an error code, but it cannot possibly fail in a well-formed program. Checking for an error for mutex unlock is pointless: what would you do in response?

When "cannot happen" happens:

1. stop everything

2. coredump (if applicable)

3. return -1 from main

Re: fork() can fail

#223
post #14

Earlier quoted context omitted.

When you see chdir, or any notion of the current working directory being used for anything: run as fast as you can. (or refactor if it's not too late). Things I've seen because of software relying on it.. Sometimes it's just directories/files it creates popping up all over the place, sometimes it's 'just' crashing, but yes sometimes it starts to erase and all hell really breaks loose.

If you can't rely on current working directories then you have to specify any file locations absolutely? That doesn't seem like a good idea because then your code quickly turns into a hot mess if you ever have to change where stuff lives. This is such a stupid problem I run into a lot. Both alternatives (doing things with absolute paths vs doing things entirely with relative paths) seem to have a lot of downsides. Ov…

That doesn't seem like a good idea because then your code quickly turns into a hot mess if you ever have to change where stuff lives.

It doesn't turn into a mess if you handle it correctly from the start. The way we ususally handle this in large applications is to have one single class like 'ApplicationPaths' which internally figures out all paths needed. No other code uses paths directly, instead always uses paths relative to ApplicationPaths.AppConfigDir/ApplicationPaths.UserConfigDir/ApplicationPaths.ExecutableDir and so on.

Re: fork() can fail

#224
post #213

Earlier quoted context omitted.

> ...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…

It would only be possible if a limit were enforced on all non-primary namespaces. However something that has been /possible/ for a while (but not in practice done) would be to elevate root process priority over other processes. Probably not done due to daemons needing to run as root (which is decreasing as they're able to drop privileges these days).

Root has had the ability to assign negative nice values since long, long ago. Non-root users can only assign positive niceness. The range is -20 - +19.

In theory this can give higher priority to a process, but if you cannot get into the run-queue at all (fork bomb), or the problem is in kernel space (e.g., I/O access, hang, or a kernel space loop), then it's not going to help you much.

Re: fork() can fail

#225
post #213
post #209

When 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…

It's not specifically the lack of cpu timeslices that crowds out other programs, it's more like exhaustion of all the OS resources (process table fills up, file table fills up, memory runs out, swap death etc).

Sure if you carefully made everything fork-bomb-resistant then a cpu quota would be a part of it. Container systems use fork bombs as basic test cases.

Re: fork() can fail

#226
post #41

Seems Python handles this correctly (by raising an exception): >>> resource.setrlimit(resource.RLIMIT_NPROC, (0, 0)) >>> os.fork() Traceback (most recent call last): File " ", line 1, in os.fork() OSError: [Errno 11] Resource temporarily unavailable

There are plenty of little nice things like this in python that save you. So if you're porting python code to other platforms... be very careful!

Re: fork() can fail

#227
That's why you read the manpage on a function before you apply it rather than just cutting-and-pasting the first bit of code google returns when you search for 'fork example unix'.

(In this particular case that actually returns (for me) a bit of code that gets it right.)

Re: fork() can fail

#228

Earlier quoted context omitted.

> cannot possibly fail in a well-formed program I think that's your answer. A mutex error return probably indicates an application bug, such as double unlock. You should probably assert or abort on "can't happen" mutex errors. Programmers are lazy. If they take the time to document an error return value, then you should probably heed their warnings. :)

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

#229

Earlier quoted context omitted.

> cannot possibly fail in a well-formed program I think that's your answer. A mutex error return probably indicates an application bug, such as double unlock. You should probably assert or abort on "can't happen" mutex errors. Programmers are lazy. If they take the time to document an error return value, then you should probably heed their warnings. :)

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.

Never ever put actual code in asserts, not even through clever macros. Stick the return value in a temp var, then check the contents of the temp var in your assertion.

Re: fork() can fail

#230
post #167

Earlier quoted context omitted.

In general I agree with your "don't blame the programmer" point, but I would seriously hesitate to criticize fork(). Yes, in 2014, that behavior seems uncommon and it seems like very poor design to lump such destructive behavior into an otherwise meaningless "-1"... but remember that fork was not written in 2014. It was written forty-five years ago . I'm not saying it was a great API design decision back then, but I'…

I think azinman2 was criticizing kill(), not fork(). It would make more sense to have a separate system call, something like killall().

You can criticise both, and more importantly criticise C for its inability to create sensible APIs: in a good design, fork() would have exclusive domains for a PID, an Error and a Child result and you couldn't confuse an error for a pid.
Post reply on HN