Search code examples
c++cfork

Different C++ fork() behavior between CentOS 7.5 & RockyLinux 8.4, Ubunu 20.04


I'm working with some legacy code. It works fine on a CentOS 7 system. The args array gets hosed on both a Rocky 8.4 and Ubuntu 20.04 system. I've simplified the problem and added print statements. The execv() was launching another program. The args going into the execv get messed up. Without the fork, the code works as expected. Baffled.

I have two simple test programs, one of which does nothing.

test9.cpp

int main(){}

and test10.cpp

#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
int main()
{
   std::vector<std::string> stringArgs;
   std::string a{"./test9.x"};
   std::string b{"test10.cpp"};
   stringArgs.push_back(a);
   stringArgs.push_back(b);
        char* args[stringArgs.size()+1];
   if(fork() == 0){
        for(uint8_t i = 0; i < stringArgs.size(); i++) {
            std::string tmp(stringArgs[i]);
            args[i] = const_cast<char*>(tmp.c_str());
        std::cout << "\n\t"<<args[i]<<"'\n\n";
        }
        std::cout << "\n\t"<<args[0]<<"'\n\n";
        std::cout << "\n\t"<<args[1]<<"'\n\n";
        // last argument has to be NULL
        args[stringArgs.size()] = NULL;
    
        execv(args[0],&args[0]);
        std::cout << "\n\tERROR: Could not run '"<<args[0]<<"'\n\n";
   }
   else
    std::cout<<"parent\n";
}

g++ -o test9.x test9.cpp; g++ -o test10.x test10.cpp

On the CentOS 7 I get:

$ ./test10.x

    ./test9.x


    test10.cpp


    ./test9.x


    test10.cpp

    parent

And on both Rocky Linux 8.4 and Ubuntu 20.04 I get this. Notice the test9.x gets replaced by test10.cpp after the for loop.

./test10.x
parent

    ./test9.x


    test10.cpp


    test10.cpp


    test10.cpp


    ERROR: Could not run test10.cpp

Solution

  • THis loop

       for(uint8_t i = 0; i < stringArgs.size(); i++) {
            std::string tmp(stringArgs[i]);
            args[i] = const_cast<char*>(tmp.c_str());
            std::cout << "\n\t"<<args[i]<<"'\n\n";
        }
    

    is creating an array of pointers to a temporary on the stack, or some internal implementation defined part of std::string

    do this instead

       for(uint8_t i = 0; i < stringArgs.size(); i++) {
            args[i] = strdup(stringArgs[i]);
            std::cout << "\n\t"<<args[i]<<"'\n\n";
        }