Tuesday, March 1, 2011

Debuging random segvs

This code is a simple and Focused segv catcher, it is designed for transient and random errors, the ones where you never know when or if they are going to happen. The idea is to use a local varable to scope the monitered area and keep tabs of the last line of code with the jump function. There is a streaming mech to gather input params and other data along the way(ie you can log the local vars in it after the fact). Then when a segv actually happens it wakes up and informs you of where it feel over and what the logged data was.

#include <csignal>
#include <iostream>
#include <stdlib.h>
#include <sstream>
 
namespace SigCatchDebug
{
void (*original)(int);
bool installed = false;
std::string   file_;
int           line_  = 0;

std::stringstream data;

void debug_sig(int type)
{
    if(line_ != 0)
    {
        std::cout << "Signal Caught!!!" << std::endl
                  << "last trace loc:" << file_ << ":" << line_ << std::endl
                  << "----- data was ---- "                     << std::endl
                  << data.str() << std::endl
                  << std::endl;
    }

    if(original != SIG_DFL ||
       original != SIG_IGN)
        (*original)(type);
    
    std::exit(EXIT_FAILURE);  //<<-- this really needs to be here!
}

class AutoScope
{
public:
    AutoScope(const char* file,
              const int   line)
    {
        if(!installed)
        {
            installed = true;

            original = std::signal (SIGSEGV,debug_sig);
            if (original == SIG_ERR)
            {
                std::cout << "signal implosion" << std::endl;
            }            
            //std::cout << "signal installed" << std::endl;
        }
        
        file_        = file;
        line_        = line;

        data.str("");
    }

    template<typename T>
    inline AutoScope& operator<<(const T& t) throw()
    {
        try
        {
            data << t;
        }
        catch (...)
        {}
        return *this;
    }

    ~AutoScope()    
    {
        //std::cout << "signal disable" << std::endl;
        line_ = 0;
    }

    void jump(int line)
    {
        line_ = line;
    }

};

}

void evil_random_crashing_func()
{
    static count = 0;
    char** test = NULL;

    SigCatchDebug::AutoScope sigScope(__FILE__,__LINE__);
    sigScope << "test: " << test << "\n"
             << "count: " << count;

    sigScope.jump(__LINE__);
    if(count == 3)
        test[0] = "ABCDEFG";

    sigScope.jump(__LINE__);
    if(count == 4)
         std::cout << "evil_random_crashing_func: " << test[0] << std::endl;
    
    std::cout << "Evil " << count << std::endl;
    count++;
}

void evil_random_crashing_func2()
{
    char** test = NULL;

    test[0] = "ABCDEFG";
    std::cout << "evil_random_crashing_func2: " << test[0] << std::endl;
}

int main(int argc, char const * const *argv)
{
    try
    {
        evil_random_crashing_func();
        evil_random_crashing_func();
        //evil_random_crashing_func2();
        evil_random_crashing_func();
        evil_random_crashing_func();
        
    }
    catch (std::exception const &e)
    {
        std::cout << "Unexpected exception: " <<  e.what() << std::endl;
    }
    catch (...)
    {
        std::cout << "Unexpected exception" << std::endl;
    }
    return 0;
}

No comments:

Post a Comment