Live data from Hacker News

Fork() without exec() is dangerous in large programs

evanjones.ca

1–10 of 106 posts

Re: Fork() without exec() is dangerous in large programs

#3
post #2

In my opinion, it's libraries that secretly use threads under the covers (but still access state shared with the rest of the program like the malloc heap) that are what's dangerous.

guh. Those bugs aren't fun to hunt down. I don't think you really understand the importance of avoiding global or semi-global states until you have to do concurrent stuff, or when you have to start being serious about tests.

Re: Fork() without exec() is dangerous in large programs

#4
post #2

In my opinion, it's libraries that secretly use threads under the covers (but still access state shared with the rest of the program like the malloc heap) that are what's dangerous.

I dunno--under that definition every concurrent GC is "dangerous".

Re: Fork() without exec() is dangerous in large programs

#5
post #2

In my opinion, it's libraries that secretly use threads under the covers (but still access state shared with the rest of the program like the malloc heap) that are what's dangerous.

Yes. Libraries should provide algorithms and data structures, and parameterize a threading interface if necessary (though I think it's usually not necessary).

Applications can then instantiate their own threads and pass them to the library (i.e. dependency injection.)

So if you have 10 different concurrent libraries in an application, then you don't end up with 10 different threading paradigms or 10 different thread pools. This is a matter of application architecture -- libraries shouldn't bake in a specific policy.

Re: Fork() without exec() is dangerous in large programs

#6
post #4
post #2

In my opinion, it's libraries that secretly use threads under the covers (but still access state shared with the rest of the program like the malloc heap) that are what's dangerous.

I dunno--under that definition every concurrent GC is "dangerous".

What libraries need to do GC? That is a language issue and not a library issue.

When you are embedding a language like Go in a C program, its runtime becomes a library. But that's the example the proves the rule: there are (or were) well-known problems with that. Libraries shouldn't be doing GC.

Re: Fork() without exec() is dangerous in large programs

#7
fork() is not per se "dangerous" in such context. You just have to be careful enough and only use asynchronous-signal-safe fonctions, as you would do in a signal handler (see https://www.securecoding.cert.org/confluence/display/c/SIG30...)

Typically calls such as malloc(), printf() etc. are strictly forbidden in the child after a fork().

Re: Fork() without exec() is dangerous in large programs

#8
Yap. Erlang 19 (latest version) switched to using a smaller spawner executable and spawns all OS processes from there by forking. So it forks something restricted and small not the whole VM.

Here are the details of how it works:

https://github.com/erlang/otp/blob/a5256e5221aff30f6d2cc7fab...

They also claim a 3-5x speedup for launching external commands because of it. So there is a nice performance boost as well.

So basically can add 4th strategy -- fork once a small program at the start, then fork from there from then on.

Re: Fork() without exec() is dangerous in large programs

#9
The fork-exec code in my program currently does some things that are supposedly unsafe, but I can't figure what to use instead of initgroups() which is not async-signal-safe. I want to run the child as a different user for which I do initgroups+setgid+setuid between fork and exec. The only solution I see is to run getgrouplist() before the fork then in the child use setgroups() instead of initgroups(), but both of these functions are non-standard.

EDIT: Never mind, seems like initgroups() is also nonstandard but generally available on Unix-like systems.

Re: Fork() without exec() is dangerous in large programs

#10
post #2

In my opinion, it's libraries that secretly use threads under the covers (but still access state shared with the rest of the program like the malloc heap) that are what's dangerous.

I completely disagree. The only part of this that seems dangerous is the fact that it can turn a single-threaded program into a multi-threaded one, and the only real problem there is it makes fork-without-exec unsafe. But fork-without-exec is basically unsafe anyway unless you can absolutely guarantee that nothing has ever spawned a thread. Meanwhile, preventing libraries from using threading under the covers basically means throwing away lot of performance gains for no good reason.
Post reply on HN