This month’s case looks like a ghastly oversight in BoundsChecker, at least when first presented to our Customer Care and Engineering teams. The alleged bug appears to be that BoundsChecker is yielding a false negative for an uninitialized memory read. This is supposed to the ultimate BoundsChecker forte, detecting where memory misuse could lead to catastrophic process or data results. So let’s look at the boiled down code sample that shows the error:
1| #include "stdafx.h"
3| int _tmain(int argc, _TCHAR* argv)
5| char v;
6| char w;
7| v = w; /*Uninitialized Memory Read: Pointer 0x001AFA91 (1) refers to an
8| uninitialized local variable w 0x001AFA90 (10) in function wmain.*/
10| wchar_t x;
11| wchar_t y;
12| x=y; /*Uninitialized Memory Read: Pointer 0x001AFA72 (2) refers to an
13| uninitialized local variable y 0x001AFA70 (20) in function wmain.*/
15| return 0;
The bug report stated that BoundsChecker only raised an Uninitialized Read Pointer on the second instance, namely the assignment on line 12. Why was it missing essentially the same code with the assignment on line 7? The answer lies in BoundsChecker’s use of the Fill on Allocation option in Memory Tracking. By default, Fill on Allocation is set to a two byte allocation pattern for guard bytes. Since the array of wchar_t’s contains two byte elements, BoundsChecker catches this out-of-the-box. To also have it catch the assignment for the char one byte elements, you must switch the option in Memory Tracking so Fill on Allocation uses one byte guard bytes. Doing this catches both line 7 and line 12, as the comments in source depict. This was a bit of head scratcher at first blush, but in retrospect makes tons of sense.
As more new C++ code moves to Unicode, use of bare chars falls away some. But because legacy code often still contains them, and because byte arrays will never go out of style, be wary of this potential for missed events against single byte operations. Why don’t we make guard bytes one byte by default to catch this out of the box? Single byte matching raises the odds that properly initialized memory may match the one byte guard pattern, leading to extra false positive noise. Some users in fact select four byte guards to further reduce odds of matching on a purposefully initialized object. This may miss smaller objects, but all the bigger, nastier ones remain detected.