产卵儿童和执行 - 不确定的行为

Spawning children and exec - undefined behavior

本文关键字:不确定 执行      更新时间:2023-10-16

我制作了一个非常简单的程序,呼叫叉子并调用另一个问题。虽然它可以执行我想要的事情,但发生了一个错误,而cout则是循环的时间两倍。这是代码: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 = ''
    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;
}
`

另一个过程是孩子。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;
}

输出为

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

所以我在这里误解了什么?

这里被误解的是编写现代C 代码的一般原则。没有任何理由使用这些外观可怕的C风格动态内存分配。在这里完成的所有操作都可以使用容器进行得更加干净,结果代码至少要小三倍。

oh,execv的参数阵列必须由NULL指针终止。不是,所以这导致了不确定的行为。由于此垃圾参数,execv系统调用很可能会失败 - 根据我对手动页面的细读,很可能是使用EFAULT

因此,execv()实际上在子过程中返回。由于显示的代码未能检查其返回值:一个随机的子过程将在从execv()返回时继续执行,在子过程中返回main(),并继续使用其自己的for循环的自己的旋转木马。,因此导致重复输出。