views:

119

answers:

6

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.

A: 

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).

InsertNickHere
well then, i should change all of related codes. the program code is very huge so i'm thinking another way to solve.
ljh131
+1  A: 

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.

D.Shawley
cannot run this program with debugger. the problem occurs in real environment and very hard to reproduce.
ljh131
A: 

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.

lrm
unfortunately, can't use debugger or something because program runs on real condition.
ljh131
Then you'll need to wrap the value like you were doing, but stop giving back access to the underlying variable. You need to proxy every request in. Of course, if the problem is that subtle, the this very change might make it go away.
lrm
Another hacky solution might be to spawn a thread that periodically checks the value of the memory location where you see the problem. But this begs the question, what are you going to do when you detect this error at run-time. Presumably you need to inspect the program and its memory contents to understand why the problem exists.
lrm
On second thought, you're probably best off just adding logging around the critical areas. This way you can add the necessary debug information so that you can try to solve the issue after it has happened. Alternatively, if you can detect the problem after the fact, you can add an assert to make sure it hasn't happened. If it has happened, you can cause the program to exit and dump its memory contents to a dump/core file that you can inspect.
lrm
thanks to your long reply. just like what you said, if there's no way to find the problem easily, i should do modify more codes.
ljh131
A: 

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.

SigTerm
thanks to your reply. program runs on windows, but i can't use this technique. the problem caused by some logic error, not randomly writing memory. and also write to that value should be allowed.
ljh131
@ljh131: Well, in this case I can only think about hardware breakpoints. You still will need some kind of debugger, though.
SigTerm
A: 

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&.

DeadMG
ljh131
DeadMG
ahhh.. i understand. it seems only solution in this circumstance.
ljh131
A: 

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:

http://stackoverflow.com/questions/186237/program-only-crashes-as-release-build-how-to-debug

Polaris878
thanks to your reply, but what i mean is can't debug or trace with debugger because the bug is very hard to reproduce to me.the only way to find that bug is to use these techniques and see in real(by many users) condition.and it doesn't seems caused by memory overwrite.
ljh131
Are you SURE?? The symptoms you are describing sound exactly like one of the situations listed above.
Polaris878