by cryptonector | 2025-04-26 22:56:00+00:00
> Wait, I sense some genuine concern here. In fact, you tricked me into learning, which is what I also do with my students.

Haha, well, tricking you was not my intent. I'm glad I did though!

> The kernel then would have to follow [...]

The kernel doesn't have to do anything like that because the kernel doesn't know about user-space allocators. The kernel only knows about the pages used in constructing the user-land address space for the process. What you're really getting at is "fork-safety" (like thread safety, but fork fork()).

Whether using fork() or vfork(), in principle the child[0] process is only permitted to use async-signal-safe functions on the child side. It can only use async-signal safe functions, which are typically the system calls needed to do everything up to an execve() (which is also safe).

In practice however, many of us know how to write multi-process daemons that do very much use async-signals-UNsafe functions on both sides of the fork(), and it's OK if you know what you're doing, and if it's a _real_ fork(). If it's more like like a combination of threads and vfork() then it's not safe at all to use async-signal-UNsafe functions on the child side!

And malloc() (and free()!) is absolutely NOT async-signal-safe! Which is what you noticed in thinking about this.

So a fork() that creates a new thread but not a new address space, and which swaps the stack back and forth as each of the parent or child execute, is NOT safe to use with async-signal-UNsafe functions on the child side of fork().

So your fork() implementation, if I understood what it does, is probably only safe for a certain class of programs that happen to be using fork() exactly as the fork(2) man page says.

So you might need to patch some fork()-using OpenBSD programs to function correctly in MinC. And any other fork()-using programs one might want to use under MinC may also need to be patched.

Programs using posix_spawn() will be OK _if_ OpenBSD's implementation uses vfork() and the MinC kernel implements vfork().

With vfork() the danger of using anything other than async-signal-safe functions on the child-side is so much clearer that it is paradoxically and in my opinion safer than fork().

Although I called fork() "evil", I use it lots in my code. I've written many versions of daemon(3) that have the parent exit only when the child signals that it is ready (this is to avoid race conditions in multi-service systems and testing). I've written multi-processed daemons that do use async-signal-UNsafe functions on both sides of fork(). But I don't really condone that :cry-laugh:. One has to be quite aware of the dangers, and understand them, in order to use fork() like that.

BTW, I think it would be interesting to have a new try at implementing fork() in WIN32. I wonder if one can create a copy of the parent's address space in the child w/o having to use any of the LoadLibrary*() functions to load DLLs, thus avoiding the ASLR issues for example. I imagine that it must be possible, but also that it must be very tricky. You can see that abandoning fork() for vfork() and spawn-type APIs would be best for running Unix software on Windows...

[1] is an implementation of daemonization that spawns a child instead of fork()-and-continue. That has an option to exec on the child-side to make it possible to test on Unix logic that otherwise would only be tested on Windows. One could use the same approach to build multi-processed servers, where you'd spawn each child rather than fork() each child -- i.e., vfork() then execve() with a special command-line option or env var to indicate "you are a worker process". OpenSSH's sshd nowadays always execs on the child-side of fork().

[0] daemon(3) inherently violates the requirement that the child-side of fork() not use async-signal-UNsafe functions, but this is OK because the real [but unstated] requirement is that only one of the parent or child may use async-signal-UNsafe functions.

[1] https://github.com/heimdal/heimdal/blob/master/lib/roken/det...