# How to watch stack variable for corruption?

• 06-03-2012
User Name:
How to watch stack variable for corruption?
I have a monster of a function that is corrupting a stack variable (an argument which was passed to the function) somehow. How can I set GDB to watch a local variable?

Here's my code:
Code:

```#define I unsigned int vector<I> primes{2, 3}; void extend_primes(I n) {     static unsigned int primorial_index = 0;     static I primorial = 2;     static vector<I> addends{1};     I base = primes.back() - primes.back() % primorial;     auto offset = addends.begin();     while(base + *offset <= primes.back())         offset++;     while(primes.back() < n)     {         while(primes.back() < n && offset < addends.end())         {             if(prime(base + *offset))                 primes.push_back(base + *offset);             offset++;         }         base += primorial;         offset = addends.begin();         if(primes.back() > primorial * primes[primorial_index + 1])         {             primorial_index++;             primorial *= primes[primorial_index];             addends = {1};             for(auto i = primorial_index + 1;primes[i] < primorial;i++)                 addends.push_back(primes[i]);             base = primes.back() - primes.back() % primorial;             auto offset = addends.begin();             while(base + *offset <= primes.back())                 offset++;         }     } }```
Somewhere in it, "n" is getting corrupted. It doesn't get corrupted when I comment out the last if-statement, but I still don't see what in that block could be corrupting it.

In case you're wondering, I'm using "I" for "unsigned int" because I plan to change it to "mpz_class" when I have GMP available.

Tyler

Edit: I know it isn't kosher to post code that can't be compiled and ran, but it's rather large and obnoxious. If anyone wants it, just say so.
• 06-03-2012
manasij7479
Quote:

How can I set GDB to watch a local variable?
You can set the watch only after getting to the scope in which the variable is visible.
• 06-04-2012
maven
you are focusing only one variable "P" which is getting corrupted. And generally for this kind of problem someone else is responsible. Read about Overwriting memory:
Code:

```int i = 0; char target [4]; strcpy (destination, "Hello world!");```
The value of the variable "i" will be overwritten.(Hence corrupted). While in GDB if you are inside your function you can always print the value of the variable using "print" p. While executing GDB you can set break point on the function extend_primes() and then execute it step by step using "next"
• 06-04-2012
Elysia
You could set memory breakpoints that will break when writing outside an area reserved for a variable.
Perhaps this might be of help: Debugging with GDB
• 06-04-2012
User Name:
Oh, it was even worse than I had thought. :eek: My prime() function calls extend_primes() and vice versa. "n" wasn't getting corrupted; extend_primes(100) was calling prime() with odd values which was causing extend_primes() to get called with odd values also. I think it is an iterator/overrun problem in extend_primes() which causes prime() to get called with random junk.

Thanks for the great suggestions. I think I'll try stepping through it to see if the problem is obvious that way and if not, I'll use memory breakpoints.
• 06-04-2012
antred
You could use std::vector::at() instead of operator [] to access individual elements. That way you'll get automatic bounds checking.
• 06-05-2012
Elysia
Be extremely careful with iterators. They are one of the most dangerous features in the language since they aren't bounds checked. They're just glorified pointers.
If you are aiming to secure your application, only use them in loops where you can be sure they are valid. Otherwise avoid them.
• 06-05-2012
Salem
GDB Documentation
5.1 Breakpoints, Watchpoints, and Catchpoints
Quote:

A watchpoint is a special breakpoint that stops your program when the value of an
expression changes. The expression may be a value of a variable, or it could involve values
of one or more variables combined by operators, such as ‘a + b’. This is sometimes called
data breakpoints. You must use a different command to set watchpoints, but aside from that, you can manage a watchpoint
like any other breakpoint: you enable, disable, and delete both breakpoints and watchpoints
using the same commands.
Set a breakpoint on extend_primes(), then enable the watchpoint on n (for writes).
• 06-05-2012
antred
Code:

```while(base + *offset <= primes.back())     offset++;```
This looks especially suspicious. You never check if your offset iterator is valid. What if you've long moved past the end of the container the iterator refers to?

If I were you, I'd pack that function full of assert()'s to verify that none of your iterators / indices are out of bounds.

Lastly, your extend_primes() function is only getting called in one thread, right? Because seeing as your function has state in it (3 static variables), it is not safe to use in a multi-threaded environment unless you use proper thread synchronization primitives to make sure one thread doesn't muck up these state variables for another thread.

Also, avoid using postincrement on iterators and prefer preincrement (i.e ++offset instead of offset++) as that tends to be more efficient.
• 06-05-2012
User Name:
I rewrote it without the need of the addends list, thus fixing a bug at the same time as improving memory efficiency.

Code:

```void extend_primes(I n) {     static unsigned int primorial_index = 0;     static I primorial = 2;     I base = primes.back() - primes.back() % primorial;     if(primes.back() != base + 1 && prime(base + 1))         primes.push_back(base + 1);     for(auto i = primorial_index + 1;primes.at(i) < primorial && primes.back() < n;i++)         if(prime(base + primes.at(i)))             primes.push_back(base + primes.at(i));     base += primorial;     while(primes.back() < n)     {         if(prime(base + 1))             primes.push_back(base + 1);         for(auto i = primorial_index + 1;primes.at(i) < primorial && primes.back() < n;i++)             if(prime(base + primes.at(i)))                 primes.push_back(base + primes.at(i));         base += primorial;         if(primes.back() > primorial * primes.at(primorial_index + 1))         {             primorial_index++;             primorial *= primes.at(primorial_index);             base = primes.back() - primes.back() % primorial;             if(primes.back() < base + 1 && prime(base + 1))                 primes.push_back(base + 1);             for(auto i = primorial_index + 1;primes.at(i) < primorial && primes.back() < n;i++)                 if(primes.back() < base + primes.at(i) && prime(base + primes.at(i)))                     primes.push_back(base + primes.at(i));             base += primorial;         }     } }```
This function generates a list of all primes less than 1000000 and the next prime in about 3.25s consistently, whereas the naive version takes approximately 14.5s consistently:
Code:

```void simple_extend_primes(I n) {     for(auto i = primes.back() + 2;primes.back() < n;i += 2)         if(prime(i))             primes.push_back(i); }```
Notice that both assume that "primes" already contains 2 and 3, at least.

antred: I'm going to add a lock. I was just getting it working before worrying about making it MT.
• 06-06-2012
Elysia
o_O
Think twice about locks. They hurt performance more than one usually thinks.
If you can, duplicate the data and let them run wild, then reduce the solution(s).