Alex R.
Alex R.

Reputation: 469

Spawning children and exec - undefined behavior

I've made a very simple program calling forking and calling another problem.While it does what I want to , a bug occurs and cout occurs double the times of for loop. Here is the code : main.cpp

`#include <iostream>
#include <cstdlib>

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>

using namespace std;

char *Strduplicate(const char *source) {
    char *dest = (char *) malloc(strlen(source) + 1); // +1 = '\0'
    if (dest == NULL)
        return NULL;
    strcpy(dest, source);
    return dest;
}

string Get_cwd(string word) {
    char cwd[256];
    getcwd(cwd, sizeof(cwd));
    strcat(cwd,"/");
    strcat(cwd,word.c_str());
    string returnVal(cwd);
    return returnVal;
}

void Call_exec(const char *name,int value) {
    char *exec_array[3];
    exec_array[0] = Strduplicate(name);
    exec_array[1] = (char *)malloc(2);
    exec_array[1] = (char *)"-m";
    asprintf(&(exec_array[2]), "%d", value);
    for (int i = 0 ; i < 3; i++)
        cout << exec_array[i] << " ";
    cout << endl;
    execv(exec_array[0],exec_array);
}

int main(int argc ,char **argv) {
    srand(time(NULL));
    /* Getting arguments */
    //........
    /* Spawning children */
    for (int i = 0 ; i < 3 ; i++ ) {
        int value = rand()%100 + 1;
        pid_t waiterpid = fork();
        if (waiterpid < 0)
            cout << "ERROR FORK" << endl;
        else if (!waiterpid) {
            string program_name = Get_cwd("child");
            Call_exec(program_name.c_str(),value);
        }
    }
    return EXIT_SUCCESS;
}
`

and the other process is child.cpp

    #include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

using namespace std;

int main(int argc ,char **argv) {
    cout << "Child #" << getpid() << " has started" << endl;
    int value;
    /* Getting arguments */
    if (argc != 3) {
        cerr << "ERROR : Wrong arguments" << endl;
        exit(EXIT_FAILURE);
    }
    else {
        if (strncmp(argv[1],"-m",2) == 0)
            value = atoi(argv[2]);
    }
    cout << "Child has " << value << endl;
    return EXIT_SUCCESS;
}

the output is

mypath/child -m 31 
mypath/child -m 23 
mypath/child -m 48 
mypath/child -m 23 
mypath/child -m 48 
alex@alex$ Child #13063 has started
Child #13062 has started
Child has 48
Child has 23
mypath/child -m 48 
Child #13064 has started
Child has 48

So what I misunderstand here?

Upvotes: 2

Views: 157

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118292

What's misunderstood here are the general principles of writing modern C++ code. There is no reason whatsoever to use these awful-looking C-style dynamic memory allocations. Everything that's done here can be done much cleaner, using containers, with the resulting code being at least three times smaller.

Oh, and execv's parameter array must be terminated by a NULL pointer. It is not, so this results in undefined behavior. Most likely, the execv system call fails, due to this garbage parameter - most likely with an EFAULT according to my perusal of its manual page.

Thusly, execv() actually returns in the child process. Since the shown code fails to check its return value: a child process, randomly, is going to continue executing upon returning from execv(), returning to main() in the child process, and continues with its own merry-go-round of the outer for loop, hence resulting in the duplicate output.

Upvotes: 1

Related Questions