开发者

C++ Tracking primitive type value change

i have a complex program with weird bug that some int value is down to zero unexpectedly.

so i want tracking this built-in type value, then i could debug easily.

to do that, i made following ValueWatcher template class so i could track almost changes of value except when ValueWatcher is dereferencing. (i made these dereferencing operators because the program needs int *, &)

template <typename T>
class ValueWatcher
{   
public:
    ValueWatcher(const T &val)
    {
        cout << "constructor with raw value " << val << endl;

        _cur = _old = val;
    }

    ValueWatcher(const ValueWatcher& vw)    
    {
        cout << "constructor with ValueWatcher " << vw._cur << endl;

        _cur = vw._cur;
    }

    ValueWatcher& operator=(const ValueWatcher &rhs)
    {
        cout << "operator= with ValueWatcher " << rhs._cur << endl;

        _cur = rhs._cur;

        onChanged();

        return *this;
    }

    ValueWatcher& operator=(const T &val)
    {
        cout << "operator= with " << val << endl;

        _cur = val;

        onChanged();

        return *this;
    }

    int *operator&()
    {
        cout << "addressing operator" << endl;

        // can't track anymore!!!!!!!!!!!!!!!!!!!!!!!!!

        return &_cur;
    }

    operator int&()
    {
        cout << "operator int&" << endl;

        // can't track anymore!!!!!!!!!!!!!!!!!!!!!!!!!

        return _cur;
    }

    operator int&() const
    {
        cout << "const operator int&" << endl;

     开发者_高级运维   return _cur;
    }

    operator int() const
    {
        cout << "operator int" << endl;

        return _cur;
    }

private:
    void onChanged()
    {
        // update old and do proper action

    }

    T _cur;
    T _old;

};

the problem is, when client code wants int & or int * of ValueWatcher, - it can gives int & or int * anyway but - int * or & cannot hold ValueWatcher instance, so can't tracking anymore.

is there anyway to solve this? i think it can be solved by returning reference or pointer class instance instead of just returning & or * of built-int type. but i don't know how to do that.

in addition- i can't run this program with debugger. the problem occurs only in REAL environment and very hard to reproduce.


If you can reproduce the behavior when running in a debugger, you should be able to set a value change or memory change breakpoint. This is probably easier than introducing a proxy implementation.


Its probably not the best solution, but what if your * or & return a pointer/reference to your value watcher? Otherwise I would forbid the use of * or &. (By not implementing it or making it private).


I don't think this is possible. Once you return an int* or int&, you've lost the ability to track anything. The only way (and the correct way, IMO) to do it that I can think of is to use a debugger and set a watch point with an appropriate condition. When the condition is met the debugger will interrupt and halt the program so you can inspect the memory, call stack, etc.


If you can spare a PAGE_SIZE bytes for your variable, then you can lock this part of memory using VirtualProtect (if you're on windows) - you can set read only access, for example. After that, anything that tries to access that variable will crash the program (so you'll be able to write memory dump and pinpoint routine that changes variable). I used this technique to pinpoint similar problem (multithreaded app, something was randomly overwriting memory blocks). If you can't debug machine immediately, try writing dumps using MiniDumpWriteDump . You will be able to debug memory dumps using WinDBG or Visual Studio.


If you're seriously desperate:

#define int ValueWatcher<int>

In a better scenario, you'd use

//typedef int intt;
typedef ValueWatcher<int> intt;

Then re-write all your code that wants an int and replace it. Replace int* with intt*. Replace int& with intt&.


You say you only see this problem when not debugging, so I'm guessing you have a bug which is obscure and can only be seen when building with optimizations. There are a couple possible explanations for this behavior:

  • You have a race condition somewhere

  • You didn't initialize a variable properly... so when building with optimizations you're values are initialized differently than when debugging.

  • You have a buffer overrun somewhere which is writing over one of your variables. Again, this could be something you only see when built with optimizations... When you build for debugging the compiler is going to leave extra space around variables on the stack... which acts as a cushion and can keep some bugs from revealing themselves.

Here is a relevant SO post which explains these issues in more detail:

Program only crashes as release build -- how to debug?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜