More pages: 1 2 3
Dealing with uninitalized memory
Friday, June 18, 2010 | Permalink
A common source of undeterministic bugs that are hard to find is uninitialized variables. In a local scope this is typically detected by the compiler, but for member variables in a class you're typically on your own. You forget to initialize a bool and in 255 cases of 256 you get 'true', so the code might appear to work if that's a reasonable initial value. Until your bool ends up on a memory address with a zero in that byte.
One way to deal with this problem is to simply initialize all memory to zero first thing in the constructor. Unfortunately, that adds a runtime cost and code size cost. I figured someone must have attacked this problem before, and I'm sure someone did, but googling on it I haven't found much about it. So I came up with my own approach, which I'll be adding to Framework4. Basically it's a small class and a set of macros to simplify stuff. In my class definition I just tag the range of variables I want to check, typically all of them.
class MyClass
{
public:
MyClass();
...
private:
CLASS_BEGIN()
// Variables go here
CLASS_END()
};
This inserts a start and end tag into the class, which are basically two uint32.
In the constructor I do this:
MyClass::MyClass() : CLASS_INIT()
{
...
}
CLASS_INIT() will initialize all memory between the tags to 0xBAADCODE, before any other initialization happens.
At some point where I expect everything to be set up, for instance the end of the constructor or maybe after some call to Init() or whatever, I simply add CLASS_VERIFY() which will check that no memory is left as 0xBAADCODE. Also, it will check start and end tags to make sure they have not been touched, which will also detect common out of range writes.
Adding this to my simple test app I found a whole bunch of variables I didn't initialize. Most of them were simply unused though. I can't imagine what kind of bug could be avoided if something like this is added to the main system classes in a big scale project. And the best of all, this come at no extra cost at runtime because in final builds those macros are defined to nothing.
diegopark
Sunday, June 20, 2010
Although a paid application, I suggest Visual Lint / PC-Lint
idinev
Sunday, June 27, 2010
Override new/delete
extern void * _cdecl operator new (size_t size);
extern void * operator new[] (size_t size);
extern void _cdecl operator delete (void * ptr);
extern void operator delete[] (void * ptr);
Zero-initialize in 'new', with a fast memfill func ("rep stosd" may suffice), that's before setting-up the vTable ptr.
Only problematic area will remain the stack-allocated classes.
Humus
Sunday, June 27, 2010
The obvious downside of that is that it comes with some overhead because in a well written class that initializes everything itself the memory will be written twice at every creation. Also, as you mentioned, it doesn't cover the stack-allocated case, although this problem is more common on big classes who normally are not allocated on the stack. However, the very weak spot of this is reuse of already allocated memory from pool, and in-place creation, which are common things in games for performance reasons.
galop1n
Monday, July 12, 2010
Hi,
I am not a big fan of your solution. If you use a real class with a real constructor between the markers, it will erase any wanted initialization. The two introduced member will change the size of the structure and you will also initialize padding between two members of different alignment that should remains untouched
niko
Friday, November 12, 2010
Resurecting old thread, oh my..
Valgrind is the tool of choice, atleast for me, when debuging memory problems. Amongst other things it will report any use of uninialized memory.
However its only available on "Real Operating Systems". With Windows it won't help...
More pages: 1 2 3