|
From: John R.
|
Nicholas Nethercote wrote: > In the recent Valgrind survey five people complained about the > difficulty of tracking down the root cause of undefined value errors, > caused by the fact that Memcheck waits until an undefined value can > affect the visible behaviour of the program (eg. is used in a > conditional branch, or a syscall input). [snip] > It has been suggested that an option be present to do this eager > checking, but I'm not convinced it would be useful given the > overwhelming number of false positives. I'm wondering what other people > think. Thank you, Nicholas, for continuing to explore eager undef checking. One of the quality control policies that I deal with demands that an application must never fetch uninitialized bits from memory. This policy increases run-to-run repeatability when "unrelated" logic errors occur. Such repeatability makes maintenance easier, and increases reliability over the software lifecycle. The policy also increases compliance with ISO C 1989, which says that any use of uninitialized bits makes execution totally indeterminate. Language lawyers argue whether "mere fetch" constitutes "use," but an addition operation whose inputs contain uninit bits certainly is a use, even though non-eager memcheck will not complain until the sum affects I/O or flow of control. The policy makes developers aware of alignment holes and padding in structures. Often the response is "memset(&Struct, 0, sizeof(Struct));" shortly after declaration. This can increase runtime efficiency, particularly when the compiler "understands" memset(,0,) and thus elides subsequent "Struct.member<k> = 0;", or when the hardware has special instructions to clear entire cache lines. Of course, it can hurt on processors such as i586 Intel PentiumPlain/MMX, where a write miss does not allocate a cache line. But then memset can insert a fetch, for which i586 does allocate a new cache line upon miss. And memcheck can learn this specific exception, just like memcheck can learn about the intentional fetch overruns in strlen, strcpy, memcpy, etc. If the fundamental low-level language runtime libraries fetch uninit bits in their internal operation, then eager memcheck will notice, and the resulting "noise" will be bothersome. As a contribution towards eliminating this problem, from time to time I have "cleaned up" glibc so that its own internal testcases fetch no uninit bits. See my web page http://BitWagon.com/glibc-audit/glibc-audit.html Just as the first encounter between an application and memcheck often causes dismay, so the first encounter with eager memcheck is likely to be even more daunting. But "thousands" of complaints can be handled with just a few memset(), and this is heartening. Even junior team members can be productive at this stage. Finding alignment holes or padding in an applications's "basic" structs can be a wakeup call for storage efficiency. And if you keep track, within a week or two you might notice that the number and frequency of non-reproducible behaviors is decreasing. Bugs "cascade" less often; the original bug, the first misuse, tends to become visible immediately rather than after infecting several other areas of control or data. -- |