views:

84

answers:

4

Hello,

Sorry I can't be specific with code, but the problems I am seeing are anomalous. Character string values seem to be getting changed depending on other, unrelated code. For example, the value of the argument that is passed around below will change merely depending on if I comment out one or two of the fprintf() calls! By the last fprintf() the value is typically completely empty (and no, I have checked to make sure I am not modifying the argument directly... all I have to do is comment out a fprintf() or add another fprintf() and the value of the string will change at certain points!):

static process_args(char *arg) {
    /* debug */
    fprintf(stderr, "Function arg is %s\n", arg);

    ...do a bunch of stuff including call another function that uses alloc()...

    /* debug */
    fprintf(stderr, "Function arg is now %s\n", arg);    
}

int main(int argc, char *argv[]) {
    char *my_arg;

    ... do a bunch of stuff ...

    /* just to show you it's nothing to do with the argv array */
    my_string = strdup(argv[1]);

    /* debug */
    fprintf(stderr, "Argument 1 is %s\n", my_string);

    process_args(my_string);
}

There's more code all around, so I can't ask for someone to debug my program -- what I want to know is HOW can I debug why character strings like this are getting their memory changed or overwritten based on unrelated code. Is my memory limited? My stack too small? How do I tell? What else can I do to track down the issue? My program isn't huge, it's like a thousand lines of code give or take and a couple dynamically linked external libs, but nothing out of the ordinary.

HELP! TIA!

+6  A: 

Simple:

  1. Learn to use Valgrind, specifically memcheck
  2. Learn to use GDB including break points and variable inspection
  3. Practice makes perfect.

That should sort it. Make sure you compile any libraries with the -g option on GCC, which keeps debugging symbols so your debugging output makes more sense.

Aiden Bell
Wow! Fast answer! First valgrind attempt tells me "permission denied" to run my program, so I have to figure it out. But if I am running into a memory problem, what's my first step in making sure my program will have enough?
EBM
Unless you have a very very tiny memory, you are ok. Run memcheck and examine the output. You will have many more than you think, and they take time to learn what they mean ... they often seem mysterious
Aiden Bell
OK, that's what I was hoping, but I am stumped. Valgrind tells me I leaked 90 bytes, which doesn't seem like a lot, no other big errors, but if it's the right 90 bytes, maybe that's the issue. Anyway, guess I have to do some digging and learning. Thank you.
EBM
Valgrind rules. +1
Norman Ramsey
Thanks again. It appears to have been a scope problem. valgrind alerted me to it by telling me "Conditional jump or move depends on uninitialised value(s)", so that was the ticket. The string was defined in a function as a character array (ala char[100]) and fell out of scope I believe. Changing its declaration to use malloc() did the trick. Bonus is now valgrind has validated that I have no errors. :-)
EBM
That is always sweet. "No leaks found". Good luck with it all!
Aiden Bell
+1  A: 

If you are writing user-level applications, Valgrind is a good choice to detect memory problems such as memory leaks, buffer overflow, etc. Here is a quick start guide: http://valgrind.org/docs/manual/QuickStart.html

ZelluX
Thanks, this seems to be where I need to go next
EBM
A: 

You don't give your dev tools, but if you're like 90% of coders you're already using an IDE with a debugger which can handle this, no new tools required. Set a watch on the chunk of memory holding your strings, then step through your code and see when the strings get changed.

Conrad Albrecht
No, no IDE. Looks like valgrind is the tool of choice, so I have to do some learning.
EBM
+2  A: 

There are two cases to consider:

  1. The arg variable changes value between the start and finish of process_args.
  2. The arg stays the same, but the string it points to is changed.

Your description and your code doesn't differentiate between the two, but it's important to know which of the two is actually happening.

This will reveal the answer:

fprintf(stderr, "Function arg is %s (%p)\n", arg, (void *)arg);
... do bunch of stuff ...
fprintf(stderr, "Function arg is now %s (%p)\n", arg, (void *)arg);

Most often arg is not changing (i.e. you have case 2). If so, something is corrupting the string you've allocated. Valgrind, suggested already, but available only on Linux, AIX and MacOSX, has only a 50:50 chance of finding the problem. What you really want is a GDB watchpoint: set breakpoint at the start of process_args, once hit, do (gdb) watch *(long*)arg and continue. GDB will stop when something writes to *arg (it will actually stop on the next instruction). Then use (gdb) where command to figure out what's happening.

If you actually have arg changing its value (case 1), that may be harder to debug, and indicates stack corruption of some sort, or a violation of procedure calling conventions for your platform. Valgrind will likely not help at all with that. This is more consistent with the behavior you described: commenting out unrelated code causes the bug to shift.

I can't give any further advice on debugging case 1 though, since you haven't revealed what your actual platform is.

Employed Russian
Ah, check the pointer address, good advice. I did that and verified that the pointer remains static. The data/memory is in fact what is changing, then.My platform is FC5 I think it is (yes, old, but it's offline, test only). Hmm, you think valgrind won't be as helpful? Well, guess I have to keep trying. THANK YOU FOR THE EXCELLENT ADVICE!
EBM
Yes - GDB watchpoints are likely to be the best tool for this job (Valgrind can only help if you're writing to memory you shouldn't be - rather than writing to memory that you should be in a place that you shouldn't). To look for the "case 1" problem, you can just set a watch on `arg` itself (`watch arg`).
caf
The "watch arg" is useless, because arg never changes. What you really want is "watch *arg", except that will only detect a change to the first character of the string.
Employed Russian
Employed Russian, THANK YOU. I wish I could select two answers, because your advice is great and highly appreciated. The problem was that the function where the string was originally populated declared it as a character array as such:char string[100];And that goes out of scope I think. Changing to this fixed it:char *string = malloc(100);Thanks again.
EBM