Forking process UB?

I just learned that forking a process (fork(2) - Linux manual page) might lead to problems with mutexes, condition variables etc. Does that mean that using the Rust standard library and calling fork can lead to UB? At least chrisd mentions in following thread
Why no `fork()` in `std::process`? - #4 by RalfJung - libs - Rust Internals that it is definitely unsafe!.

I wonder which parts of the standard library are still safe to use in the parent process before the fork call? Or to phrase it more practically how can I determine whether some standard library feature / container is "free" from multi-threading?

Example:
Lets say I have created an instance of std::Vec<...> and stored it in some static variable [... lazy_static! ...]. Is this vector still safe to use after the fork? I mean, besides thread safety it would also require that pointer addresses are still valid after the fork, right?

I don't think there is anything in the standard library that will spawn threads other than user-code calls to thread::spawn and thread::Scope::spawn.

Forked processes generally have an identical address space to the parent process post-fork so pointers to your example Vec will still be valid.

that's what I needed to hear :slight_smile:

One fork-related piece of Rust documentation is CommandExt::pre_exec() — when spawning a child process, it runs code after the fork and before the exec, so it has to tell you about what's safe in a forked process.

This closure will be run in the context of the child process after a fork. This primarily means that any modifications made to memory on behalf of this closure will not be visible to the parent process. This is often a very constrained environment where normal operations like malloc, accessing environment variables through std::env or acquiring a mutex are not guaranteed to work (due to other threads perhaps still running when the fork was run).

For further details refer to the POSIX fork() specification and the equivalent documentation for any targeted platform, especially the requirements around async-signal-safety.

So, it's more restrictive than you might think — note the mention of memory allocation, mutexes and env not being allowed. A good rule to start with might be that all the code run after fork needs to be no_std code (since that implies no syscalls), and then when you want to do something more than that, you check the documentation.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.