0

After running ltrace -S on two programs that were compiled by gcc (version 5.4.0), one that calls vfork() and one that calls fork(), I find that vfork() calls SYS_vfork whilst fork() calls SYS_clone.  I could not find any information about this specific behavior anywhere (some sources say each of fork(), vfork() and clone() are implemented by the correspondingly named sys_ call, whilst other sources say all three calls are implemented using sys_clone).

Source code:

#include<stdio.h>
main()
{
        int pid;
        pid=vfork();
}

Output from ltrace -S:

...
__libc_start_main([some stuff here] <unfinished ...>
vfork([more stuff] <unfinished ...>
SYS_vfork([more stuff])
--- SIGCHLD (Child exited) ---

Is there a reason libc uses SYS_vfork for vfork() but doesn't use SYS_fork for fork()?  I’ve read Thomas Nyman’s answer to Which file in kernel specifies fork(), vfork()… to use sys_clone() system call, which says:

vfork() in turn is implemented via a separate CLONE_VFORK flag, which will cause the parent process to sleep until the child process wakes it via a signal. The child will be the sole thread of execution in the parent's namespace, until it calls exec() or exits. The child is not allowed to write to the memory. The corresponding clone() call could be as follows:

clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)

This seems to be at odds with what I've observed of the output of ltrace -S.

Did I mess something up or did the glibc writers deliberately choose to implement vfork() using SYS_vfork instead of SYS_clone for a reason? Is this considered something that could change at any time or can we rely on it?

  • Mostly good info can be read in "Linux Kernel Development" 3rd edition by Robert Love in chapter 3 "Maintenance of processes". This chapter has detailed info. – Yurij Goncharuk Mar 26 '18 at 23:00
  • Your example invokes undefined behaviour because the forked child neither calls _exit() nor exec(). For example, on a Fedora 27 box it just segfaults. See gist.github.com/gsauthof/d562355dc8e220c9cf8d2faa921388d0 for a more complete minimal example. – maxschlepzig Oct 27 '18 at 7:55
4

Did I mess something up or did the glibc writers deliberately choose to implement vfork() using SYS_vfork instead of SYS_clone for a reason?

Historically, I think it’s more likely that this is simply a result of vfork not needing to be changed. Both vfork and fork initially used the equivalent system calls. When NPTL threading was implemented, the fork implementation was changed to use clone, because the C library needs to reset the thread id. vfork doesn’t need to worry about threads, because it’s only intended for use with execve (which is going to reset all that state anyway), so it was left untouched.

The NPTL design paper explains why the fork system call isn’t sufficient to implement the fork library call when threads are liable to be used:

To implement the fork function without memory leaks it is necessary that the memory used for stacks and other internal information of all threads except the thread calling fork is reclaimed. The kernel cannot help in this situation.


Is this considered something that could change at any time or can we rely on it?

Since you’re using the C library to fork, you can only rely on the C library providing the behaviour documented in the APIs; you can’t rely on a specific implementation. You shouldn’t rely on vfork(3) using the vfork(2) system call instead of clone(2), nor should you rely on fork(3) using clone(2) instead of fork(2). Note that the system calls which are used can vary from one architecture to another...

If you really need to rely on specific system calls, you should use those directly and forego the C library wrappers.

2

man 2 fork:

C library/kernel differences
Since version 2.3.3, rather than invoking the kernel's fork() system call, the glibc fork() wrapper that is provided as part of the NPTL threading implementation invokes clone(2) with flags that provide the same effect as the traditional system call. (A call to fork() is equivalent to a call to clone(2) specifying flags as just SIGCHLD.) The glibc wrapper invokes any fork handlers that have been established using pthread_atfork(3).

  • Hum yes I answered a bit too fast, there are two questions and I addressed only one – A.B Mar 26 '18 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.