Thread: How to watch stack variable for corruption?

  1. #1
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587

    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.

    Thanks for your time,
    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.
    Last edited by User Name:; 06-03-2012 at 10:14 PM.

  2. #2
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    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.

  3. #3
    Registered User
    Join Date
    Dec 2005
    Posts
    136
    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"
    S_ccess is waiting for u. Go Ahead, put u there.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    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
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    Oh, it was even worse than I had thought. 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.
    Last edited by User Name:; 06-04-2012 at 02:38 PM.

  6. #6
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    You could use std::vector::at() instead of operator [] to access individual elements. That way you'll get automatic bounds checking.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    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.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    GDB Documentation
    5.1 Breakpoints, Watchpoints, and Catchpoints
    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).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    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.

  10. #10
    Password:
    Join Date
    Dec 2009
    Location
    NC
    Posts
    587
    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.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    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).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Stack corruption ?
    By MarkZWEERS in forum C++ Programming
    Replies: 3
    Last Post: 01-31-2011, 06:03 PM
  2. watch variable??
    By haochao in forum C++ Programming
    Replies: 8
    Last Post: 10-12-2008, 12:34 PM
  3. Stack corruption by class destructor
    By qxcdfg in forum C++ Programming
    Replies: 11
    Last Post: 03-10-2008, 03:03 PM
  4. Unknown Stack corruption
    By cunnus88 in forum C++ Programming
    Replies: 2
    Last Post: 01-29-2006, 03:09 PM
  5. Environment variable corruption
    By miclus in forum Linux Programming
    Replies: 7
    Last Post: 10-01-2004, 01:45 PM