Search code examples
linuxgccprocessgdbclone

Calling "clone()" on linux but it seems to malfunction


A simple test program, I expect it will "clone" to fork a child process, and each process can execute till its end

#include<stdio.h>
#include<sched.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
int f(void*arg)
{
pid_t pid=getpid();
printf("child pid=%d\n",pid);
}
char buf[1024];
int main()
{
    printf("before clone\n");
    int pid=clone(f,buf,CLONE_VM|CLONE_VFORK,NULL);
    if(pid==-1){
        printf("%d\n",errno);
        return 1;
    }
    waitpid(pid,NULL,0);
    printf("after clone\n");
    printf("father pid=%d\n",getpid());
    return 0;
}

Ru it:

$g++ testClone.cpp && ./a.out
before clone

It didn't print what I expected. Seems after "clone" the program is in unknown state and then quit. I tried gdb and it prints:

Breakpoint 1, main () at testClone.cpp:15
(gdb) n-
before clone
(gdb) n-
waiting for new child: No child processes.
(gdb) n-
Single stepping until exit from function clone@plt,-
which has no line number information.

If I remove the line of "waitpid", then gdb prints another kind of weird information.

(gdb) n-
before clone
(gdb) n-
Detaching after fork from child process 26709.
warning: Unexpected waitpid result 000000 when waiting for vfork-done
Cannot remove breakpoints because program is no longer writable.
It might be running in another process.
Further execution is probably impossible.
0x00007fb18a446bf1 in clone () from /lib64/libc.so.6
ptrace: No such process.

Where did I get wrong in my program?


Solution

  • The second argument to clone is a pointer to the child's stack. As per the manual page for clone(2):

    Stacks grow downward on all processors that run Linux (except the HP PA processors), so child_stack usually points to the topmost address of the memory space set up for the child stack.

    Also, 1024 bytes is a paltry amount for a stack. The following modified version of your program appears to run correctly:

    // #define _GNU_SOURCE   // may be needed if compiled as C instead of C++
    #include <stdio.h>
    #include <sched.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <errno.h>
    
    int f(void*arg)
    {
        pid_t pid=getpid();
        printf("child pid=%d\n",pid);
        return 0;
    }
    char buf[1024*1024];   // *** allocate more stack ***
    int main()
    {
        printf("before clone\n");
        int pid=clone(f,buf+sizeof(buf),CLONE_VM|CLONE_VFORK,NULL);
             // *** in previous line: pointer is to *end* of stack ***
        if(pid==-1){
            printf("%d\n",errno);
            return 1;
        }
        waitpid(pid,NULL,0);
        printf("after clone\n");
        printf("father pid=%d\n",getpid());
        return 0;
    }
    

    Also, @Employed Russian is right -- you probably shouldn't use clone except if you're trying to have some fun. Either fork or vfork are more sensible interfaces to clone whenever they meet your needs.