0

I am attempting to send a command that runs a specific python script: however, whenever the program reaches the execution line, this occurs:

Unhandled exception at 0x69bd1f16 in GameServer.exe: 0xC0000005: Access violation reading location 0x46f520ca.

The program stops resonding and crashes. Here is the method in question:

void ScriptManager::runScript(std::string scriptName, std::string args[])
{
    std::string py = "python " + scriptName;
    std::cout << py << std::endl;
    for(int i = 0; i < args->length(); i++)
    {
        py += " " + args[i];
        std::cout << py << std::endl;
    }
    std::cout << py << std::endl;

    std::system(py.c_str());

}

This calls the above function:

void DBFactory::dbRegisterUser(std::string username, std::string password)
{
    ScriptManager script;
    std::string data[] = {username, password};

    script.runScript("Python.py", data);
}

The script does not run, as far as I know. I can also post the script if it would help.

Charsmud
  • 183
  • 1
  • 4
  • 19
  • 1
    The loop over `args->length()` looks wrong. That is the length of the first string, i.e. `args[0]`. Can you show the code that calls this function? – juanchopanza Jun 01 '14 at 18:28
  • Yes. I've updated the post with the function. – Charsmud Jun 01 '14 at 18:32
  • You will need to pass the length of the array to the function, or use a function template that can deduce the array's length information. See http://stackoverflow.com/questions/1328223/sizeof-array-passed-as-parameter. – juanchopanza Jun 01 '14 at 18:40
  • Hm... It appears that the command is being constructed correctly (python Python.py arg1 arg2), but the execution is throwing the error. Unless I'm misunderstanding what you're saying? – Charsmud Jun 01 '14 at 18:53
  • `args->length()` is the length of `args[0]`, i.e. `username`. Not the number of elements in `args`. – juanchopanza Jun 01 '14 at 18:55
  • The command is being constructed correctly though? For example, if the array contained [Charsmud, juanchopanza], the command does create "python Python.py Charsmud juanchopanza". – Charsmud Jun 01 '14 at 18:59
  • [I seriously doubt it](http://ideone.com/AWstMy). You go out of bounds after two iterations. Print out `args->length()` and see for yourself. – juanchopanza Jun 01 '14 at 19:03
  • OK, I think I understand.... So, how would you propose fixing it? Could switching over to a vector of strings work better? – Charsmud Jun 01 '14 at 19:08
  • `vector` of strings would be a good solution. There are other ways, but it is the simplest and easiest to understand. – juanchopanza Jun 01 '14 at 19:09

1 Answers1

1

This is the problem:

for (int i = 0; i < args->length(); i++)
{
    py += " " + args[i];
    std::cout << py << std::endl;
}

args->length() is equivalent to args[0].length(); i.e. you're taking the length of the first string in the array and using that as an index. After two iterations pass, you're going to access past the end of the array. The best solutions are(all examples are UNTESTED):

  1. Use an std::array(C++11 only):

    void DBFactory::dbRegisterUser(std::string username, std::string password)
    {
        ScriptManager script;
    
        script.runScript("Python.py", {username, password});
    }
    
    void ScriptManager::runScript(std::string scriptName, std::array<std::string, 2> args)
    {
        std::string py = "python " + scriptName;
        std::cout << py << std::endl;
        for (std::string s : args)
        {
                py += " " + s;
                std::cout << py << std::endl;
        }
        std::cout << py << std::endl;
    
        std::system(py.c_str());
    }
    
  2. Use an std::vector(the example uses C++03):

    void DBFactory::dbRegisterUser(std::string username, std::string password)
    {
        ScriptManager script;
        int tmp[2] = {username, password};
    
        script.runScript("Python.py", std::vector<std::string>(&tmp[0], &tmp[0]+2));
    }
    
    void ScriptManager::runScript(std::string scriptName, std::vector<std::string> args)
    {
        std::string py = "python " + scriptName;
        std::cout << py << std::endl;
        for(std::vector<std::string>::iterator it = args.begin(); it != args.end(); it++)
        {
            py += " " + *it;
            std::cout << py << std::endl;
        }
        std::cout << py << std::endl;
    
        std::system(py.c_str());
        }
    
  3. Pass the array size as a parameter:

    void DBFactory::dbRegisterUser(std::string username, std::string password)
    {
        ScriptManager script;
    
        script.runScript("Python.py", {username, password}, 2);
    }
    
    void ScriptManager::runScript(std::string scriptName, std::string args[], int size)
    {
        std::string py = "python " + scriptName;
        std::cout << py << std::endl;
        for(int i=0; i<size; i++)
        {
            py += " " + args[i];
            std::cout << py << std::endl;
        }
        std::cout << py << std::endl;
    
        std::system(py.c_str());
    }
    

I personally prefer example 1 and would avoid example 3 like the plague. Example 2 works well but probably isn't as fast as example 1.

kirbyfan64sos
  • 10,377
  • 6
  • 54
  • 75