User: Password:
|
|
Subscribe / Log in / New account

O_NOSTD

O_NOSTD

Posted Aug 27, 2009 18:09 UTC (Thu) by foom (subscriber, #14868)
In reply to: O_NOSTD by daney
Parent article: In brief

> For a multi-threaded program, O_CLOEXEC is required if you want race free operation.
> Hardly pointless.

No, it's not required. After a fork, your program is no longer multi-threaded, and you can at your
leisure close all file descriptors except those necessary for program you're about to exec, with no
race condition.


(Log in to post comments)

Third-party libraries

Posted Aug 27, 2009 20:24 UTC (Thu) by quotemstr (subscriber, #45331) [Link]

The problem is then that a third-party library might not be notified between a call to fork() and exec(). That's what pthread_atfork is for, but not everyone links against libpthread.

Even with pthread_atfork, however, you can race. Consider:

[library code]
static int fd = -1;
void mylib_atfork() {
    close(fd);
}

void mylib_dosomething() {
    fd = open(...);
    do_something_with_fd(fd);
}

If the fork happens between the return from open() and the assignment to fd, then you race and leak the file descriptor.

The real userspace solution would be for programs to just close unknown file descriptors between fork and exec. But they don't, so O_CLOEXEC is a decent facility for defensive library programing.

Now, on the other hand, this O_NOSTD business is pure junk that will uselessly take up a valuable flag bit for all eternity.

Third-party libraries

Posted Aug 27, 2009 21:33 UTC (Thu) by foom (subscriber, #14868) [Link]

The real userspace solution would be for programs to just close unknown file descriptors between fork and exec. But they don't, so O_CLOEXEC is a decent facility for defensive library programing.

Yes, this is what I've been saying -- see previous comment regarding "close_everything_but". The bug is in the code that calls fork/exec, not the code that opens a file descriptor!

Comments like this one just show how insane this whole thing is. The *bug* there is that libuuid doesn't close fds before execing a long-lived daemon! It should not be the responsibility of everyone to open all their fds with O_NOEXEC.

Third-party libraries

Posted Aug 27, 2009 21:51 UTC (Thu) by giraffedata (subscriber, #1954) [Link]

I don't see it. Never mind pthread_atfork() -- after all, the issue is exec, not fork. The alternative to O_CLOEXEC for a library that opens files under the covers would seem to be a prepare_for_exec() function exported by the library. The user makes sure he calls that before any exec().

As for the multithreaded program, it already has to serialize access to these file-descriptor-using functions anyway (you wouldn't want two threads opening that file at the same time), so it might as well synchronize prepare_for_exec() with those. This serialization could be done either in the library (i.e. the library is thread-safe), or outside. Oh, and here comes pthread_atfork(): it can make sure the serialization mechanism survives a fork that may precede the exec.

Third-party libraries

Posted Aug 27, 2009 22:54 UTC (Thu) by Los__D (guest, #15263) [Link]

Besides "prepare_for_exec()" being a horrible interface, do you really think that programmers that doesn't care to close unknown fds, would care to call it?

Third-party libraries

Posted Aug 28, 2009 1:44 UTC (Fri) by giraffedata (subscriber, #1954) [Link]

Besides "prepare_for_exec()" being a horrible interface, do you really think that programmers that doesn't care to close unknown fds, would care to call it?

That's beside the point. I was responding to a claim that there is no way to write a correct multithread program involving a third party library that opens files without O_CLOEXEC. And that that distinguishes O_CLOEXEC from the proposed O_NOSTD.

If on the other hand you just want to argue that O_CLOEXEC is convenient, with or without threads, then you're putting it in the same class as O_NOSTD.

Third-party libraries

Posted Aug 28, 2009 5:39 UTC (Fri) by Los__D (guest, #15263) [Link]

There is no other way for the library author to make sure that his library opened fds are safe.

It is hardly "convenience", but good library programming style, to make sure that internal data stays internal.

I would go so far as argue, that the naïve library user that doesn't close the fds, isn't entirely an idiot for expecting not to be responsible for library data.

Third-party libraries

Posted Aug 27, 2009 23:10 UTC (Thu) by quotemstr (subscriber, #45331) [Link]

Or you just do this (error checks omitted):
#include <pthread.h>

static int fd = -1;
static pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER;

static void mylib_beforefork() {
    pthread_mutex_lock(&fd_lock);
}

static void mylib_afterfork() {
    pthread_mutex_unlock(&fd_lock);
}

void mylib_dosomething() {
    pthread_mutex_lock(&fd_lock);
    if(fd == -1) {
        pthread_atfork(mylib_beforefork, 
                       mylib_afterfork, 
                       mylib_afterfork);
        fd = open(...);
        fcntl(fd, F_SETFD, O_CLOEXEC);
    }
    pthread_mutex_unlock(&fd_lock);

    do_something(fd);
}

Third-party libraries

Posted Sep 8, 2009 9:06 UTC (Tue) by jlokier (guest, #52227) [Link]

Doesn't work if the thread uses vfork() :-)


Copyright © 2017, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds