1
votes

I am trying to use clone() to create a child process to exec() some programs. I know that exec() replaces the original process and the process that calls it should end with it, so I use a child process to call exec(). However, for some reasons, after exec(), my parent process crashes also. Could someone tell me why is this happening? (if i replace clone with fork or vfork, it works)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sched.h>

void delNL(char * arry){    //A function to delete the newline at the end of the array
char * position;
position = strchr(arry,'\n');
*position = '\0';
}

int mySysC(char * command){                  //clone funtion
         char *cmd[10]={" "};
        int nb=0;
        int cnb=0;
        while(command[nb]!='\0'){
            char coa[10];
            int cici=0;
            while(command[nb]!=' ' && command[nb]!='\0'){
                coa[cici]=command[nb];
                nb++;
                cici++;
            }
            coa[cici]='\0';
            char *nad=(char *)malloc(10);
            strcpy(nad,coa);
            cmd[cnb]=nad;
            cnb++;
            if(command[nb]==' '){
                nb++;
            }
        }
        cmd[cnb]=NULL;
        execvp(cmd[0],cmd);
        exit(0);
}

void my_system_c(char * command){            //clone version
        void * stack = (void *)malloc(10000);
        void * stackTop = stack + 100000;
        pid_t pid = clone((void *)mySysC(command),stackTop,CLONE_THREAD,NULL);  //clone
    waitpid(pid,NULL,0);
}


int main(){
    char commdd[100];    
    char ex[10]="os_exit";
    while(1){
        printf("Please enter your command or enter \"os_exit\" to exit:\n");
        fgets(commdd,100,stdin);
        delNL(commdd);
        if(strlen(commdd)>0 && strcmp(commdd,ex)!=0){
            my_system_c(commdd);                       //select version
        }
        else if(strcmp(commdd,ex)==0) break;
        else printf("Empty command\n");
    }
    return 0;
}

execvp(cmd[0],cmd); this is what crashed the whole program. I add two prints one before and one after, the later one never runs. I don't understand because of I thought clone works just like fork, which creates a new process, and the end of the chile process won't affect the parent?

Thanks!!!

2
strongly suggest: 1) enable the warnings when compiling, then fix those warnings. 2) read/understand the MAN page for clone()user3629249
And also read the man page for strchr()wildplasser
Don't use clone(2). Leave it to gurus implementing pthreads(7). You are not one yet! Use fork(2) to create a process, and pthread_create(3) to create a posix threadBasile Starynkevitch

2 Answers

2
votes

clone(…CLONE_THREAD…) is not the clone() you're looking for. It creates a new process in the same thread group as the parent process, and:

If any of the threads in a thread group performs an execve(2), then all threads other than the thread group leader are terminated, and the new program is executed in the thread group leader.

If you are looking for a way to start a process without using fork(), consider using posix_spawn() instead.

Additionally, the stack pointer you are passing to clone() is invalid. The stack you allocate is 10,000 bytes large, but the stack pointer is 100,000 bytes beyond the start of the stack -- and 90,000 bytes beyond its end.

0
votes

This happens because you never actually call clone. This part:

clone((void *)mySysC(command), ...);

is equivalent to:

int result = mSysC(command);
void* first = (void*) result;
clone(first, ...);

so it calls your function before it ever calls clone. You need to pass it as a function pointer instead.

In addition to that, you should remove one zero from your stackTop to match the malloc, and avoid passing CLONE_THREAD since you want a new process:

void my_system_c(char * command){            //clone version
  void * stack = (void *)malloc(10000);
  void * stackTop = stack + 10000;
  pid_t pid = clone(mySysC,stackTop,0,command);  //clone
  waitpid(pid,NULL,0);
}