views:

142

answers:

3

I've got a plugin system in my project (running on linux), and part of this is that plugins have a "run" method such as:

void run(int argc, char* argv[]);

I'm calling my plugin and go to check my argv array (after doing a bunch of other stuff), and the array is corrupted. I can print the values out at the top of the function, and they're correct, but not later on in the execution. Clearly something is corrupting the heap, but I'm at a loss of how I can try to pin down exactly what's overwriting that memory. Valgrind hasn't helped me out much.

Sample code by request:

My plugin looks something like this:

void test_fileio::run(int argc, char* argv[]) {
  bool all_passed = true;

  // Prints out correctly.
  for (int ii=0; ii < argc; ii++) {
    printf("Arg[%i]: %s\n", ii, argv[ii]);
  }

  <bunch of tests snipped for brevity>

  // Prints out inccorrectly.
  for (int ii=0; ii < argc; ii++) {
    printf("Arg[%i]: %s\n", ii, argv[ii]);
  }
}

This is linked into a system that exposes it to python so I can call these plugins as python functions. So I take a string parameter to my python function and break that out thusly:

char** translate_arguments(string args, int& argc) {
  int counter = 0;
  vector<char*> str_vec;

  // Copy argument string to get rid of const modifier
  char arg_str[MAX_ARG_LEN];
  strcpy(arg_str, args.c_str());

  // Tokenize the string, splitting on spaces
  char* token = strtok(arg_str, " ");
  while (token) {
    counter++;
    str_vec.push_back(token);
    token = strtok(NULL, " ");
  }

  // Allocate array
  char** to_return = new char*[counter];
  for (int ii=0; ii < counter; ii++)
    to_return[ii] = str_vec[ii];

  // Save arg count and return
  argc = counter;
  return to_return;
}

The resulting argc and argv is then passed to the plugin mentioned above.

+2  A: 

Lookup how to use memory access breakpoints with your debugger. If you have a solid repo, this will pinpoint your problem in seconds. In windbg, it's:

ba w4 0x<address>

Where ba stands for "break on access", "w4" is "write 4 bytes" (use w8 on a 64 bit system) and "address" is obviously the address you're seeing corrupted. gdb and Visual Studio have similar capabilities.

Terry Mahaffey
Any idea how you could do that with gdb? Sounds like exactly what I'd need.
gct
Looks like http://stackoverflow.com/questions/58851/can-i-set-a-breakpoint-on-memory-access-in-gdb
Terry Mahaffey
Excellent, thanks!
gct
+2  A: 

How does translate_arguments get called? That is missing...

Does it prepare an array of pointers to chars before calling the run function in the plugin, since the run function has parameter char *argv[]?

This looks like the line that is causing trouble...judging by the code

// Allocate array
char** to_return = new char*[counter];

You are intending to allocate a pointer to pointer to chars, a double pointer, but it looks the precedence of the code is a bit mixed up? Have you tried it this way:

char** to_return = new (char *)[counter];

Also, in your for loop as shown...you are not allocating space for the string itself contained in the vector...?

for (int ii=0; ii < counter; ii++)
    to_return[ii] = str_vec[ii];

// Should it be this way...???

for (int ii=0; ii < counter; ii++)
    to_return[ii] = strdup(str_vec[ii]);

At the risk of getting downvoted as the OP did not show how the translate_arguments is called and lacking further information....and misjudging if my answer is incorrect...

Hope this helps, Best regards, Tom.

tommieb75
I agree with your second part (allocating storage for the strings). As currently written, the pointers in the vector point to data that is stored on the stack that then goes out of scope (arg_str). After translate_arguments is called, there is probably some code that ends up overwriting that space in the stack (local variables, etc).
Luke
Sure enough that seems to have solved the problem, thanks!
gct
A: 

if valgrind and code inspection dont help you could try electric fence

pm100