Live data from Hacker News

fork() can fail

rachelbythebay.com

191–200 of 320 posts

Re: fork() can fail

#191
post #188

"Unix: just enough potholes and bear traps to keep an entire valley going." If you don't understand how to use sharp tools, you may hurt yourself and others. Documentation for fork() clearly explains why and when fork() returns -1. Those that find the man page lacking or elusive may get more out of an earnest study of W. Richard Stevens' book, Advanced Programming in the UNIX Environment. In any case, every system pr…

> If you don't understand how to use sharp tools, you may hurt yourself and others. It's still bad API design when naively handling an error case kills everything. Is there an inherent reason that the error value for a pid has to be the same as the "all pids" value? Unless there's a very compelling reason, it seems like very poor design, well documented or not.

The inherent reason is that -1 is the most common error return code in C based APIs. The problem is not naively handling an error case, it's not handling an error case. Using a different value might avoid calling killall -1, but the program would still be incorrect.

This is the same sort of argument as strlcat vs strncat, and people can't agree on that one.

Re: fork() can fail

#192
post #112

Earlier quoted context omitted.

I'll have to admit I'm not very familiar with such languages, but shouldn't finally clauses and RAII be sufficient to deal with any necessary cleanup?

Exceptions disrupt the program flow at any place, including constructors and destructors. It's not easy to guarantee that you deallocate on destructors exactly the resources that were allocated at the constructor when both of them can stop their execution at any time. Finally clauses are technically enough, but each allocation needs the same level of attention non-memory resources (e.g. connections, files) get on oth…

I'm going to answer for C++, since as far as I know it's the only major language with exceptions and RAII. Correct me if I'm misunderstanding your post.

> It's not easy to guarantee that you deallocate on destructors exactly the resources that were allocated at the constructor when both of them can stop their execution at any time.

I disagree; let's take this one case at time to keep it simple:

1. Destructors: within C++, if you're in a destructor, the object was fully constructed, and thus you know the exact set of resources requiring destruction. It is idiomatic C++ that a destructor should not throw; I'll discuss why below.

2. Constructors: these certainly can throw at any moment, as resource acquisition is often fraught with failures. That said, idiomatic C++ provides mechanisms (RAII, such as std::unique_ptr) to manage the partially constructed set of resources in a constructor, such that if something goes wrong, they will be automatically released by virtue of the variable going out of scope. Once you have the resource acquisition completed, you transfer ownership of the objects to the object you're constructing, which is practically guaranteed to be exception-free, since it's usually just moving a pointer under the hood.

> Finally clauses are technically enough

I don't really think you can both stand by the fact that destructors can throw at any moment and that finally clauses are enough, without making what amounts to an apples to oranges comparison. Take, for example, this function, where we assume releasing a resource can fail:

  Foo() {
    SomeResource resource;
    // Assume the destruction of a SomeResource can fail.
    // Other actions take place, some of which may raise/throw.
  }
In this example, if the other actions throw an exception that causes Foo to itself abort, then SomeResource resource must be destructed. If we're assuming that destructor can also throw, we've now got two exceptions, and how do you handle two exceptions? (It's language dependent. Some discard an exception, some chain them, some, like C++, just terminate.)

If we translate this to using some sort of "finally" construct, say in a garbage collected language:

  def foo():
    resource = aquire_some_resource()
    try:
      # other actions that may raise/throw.
    finally:
      resource.release()  # but we're assuming this can also raise/throw.
You still have the same problem at the resource.release(): up to two exceptions can occur at a given point in the program, and you then need to know what your language does in that situation.

The general gist of this is that if the "release" of some generic resource can fail, then you have to make harder decisions about what happens during a stack unwind due to some other error because now you have two errors. Do you ignore it? Log it? (can you log it?)

If releasing a resource cannot fail, destructors (and finally clauses in languages lacking RAII-style resource management) cannot fail.

Re: fork() can fail

#194

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

man 3 assert

[deleted]

Re: fork() can fail

#195
post #186

"Unix: just enough potholes and bear traps to keep an entire valley going." If you don't understand how to use sharp tools, you may hurt yourself and others. Documentation for fork() clearly explains why and when fork() returns -1. Those that find the man page lacking or elusive may get more out of an earnest study of W. Richard Stevens' book, Advanced Programming in the UNIX Environment. In any case, every system pr…

every system programmer should own a copy I'd argue every programmer. It's such a fundamental part of computers & operating systems that key concepts will come up again and again. Just the other day I wanted to learn about Docker/CoreOS/etcd only to realize that I have an embarrassingly lacking understanding of how UNIX works. I immediately went to the library to pick up this book and begin fixing a flaw of mine (eve…

Meh. Not all programmers are on a UNIX system. Not all programmers are even on UNIX || Window.XX.

But even if there was only UNIX... the entire point of a well designed system is to allow users of the system to reason about it on a high level, not a domain-expert level or even domain-intermediate level. As programmers we reason about code without worrying too much about gate layout on silicon. As non-system programmers we should likewise not need to worry about shoddy OS design.

Re: fork() can fail

#197

Somewhat OT, but in the same neighborhood: Standard file handles are another thing you should not assume are there (though I'm not sure how to test for it programmatically). We once had a user that, for whatever reason, tweaked their Unix installations to not pass an open stderr to processes - they just got stdin and stdout (that is, file handles 0 and 1, but not 2). If you wrote to stderr anywhere in your program, i…

It's considered very impolite to close 1 or 2 without re-opening/duping it to /dev/null.

Re: fork() can fail

#198
post #7

This reminds me of one of the most epic bugs I've ever run into: mkdir("/foo", 0700); chdir("/foo"); recursively_delete_everything_in_current_directory(); Running as root, this usually worked fine: It would create a directory, move into it, and clean out any garbage left behind by a previous run before doing anything new. Running as non-root, the mkdir failed, the chdir failed, and it started eating my home directory…

The variant of this I ran into was significantly less destructive.

recursively_find_everything_in_current_directory() crashed due to a stack overflow when SetCurrentDirectory failed due to a single corrupt NTFS directory.

Re: fork() can fail

#199

I see a lot of comments blaming the programmer. This is completely the wrong attitude. Why are you treating the programmer like a machine? They're not a machine -- they're human. Regardless if they fully understand the API or not things should have have sane defaults for HUMAN FACTORS reasons. Bugs will always exist. The fact that the Linux kernel has many bugs is just one example of a code base that has over a decad…

Funny you should ask. I used kill -1 about two weeks ago. A for loop would not have worked.

Re: fork() can fail

#200
post #139

Earlier quoted context omitted.

Multiple return would be fine too. pid,err = fork()

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, and that's quite a hassle which doesn't fit well with C.

Post reply on HN