Sunday, September 23, 2007

Writing Clean Code-Microsoft techniques for developing bug-freen C programs

Always check if you have undefined cases, look at the memory copy code:
void memcpy(void *pvTo, void *pvFrom, size_t size)
{
void *pbTo = (byte *)pvTo;
void *pbFrom = (byte *)pvFrom;
ASSERT(pvTo != NULL && pvFrom != NULL);
ASSERT( pbTo >= pvFrom + size || pbFrom >= pvTo + size );
while (size-->0)
*pbTo++ = *pbFrom++;
return(pvTo);
}


'assert' is used to avoid illegal case, not error. error is allowed.

What is the problem with the following resize memory code?
pbBuf = (byte*)realloc( pbBuf, sizeNew)
if( pbBuf != NULL)
...// start to use this resized buffer

pbBuf is the only pointer to the resized memory, when realloc fails, pbBuf is filled with NULL and the only pointer to this memory block is overwritten. Memory leak happens. Look at the following codes to make it better:
flag fResizeMemory( void **ppv, size_t sizeNew)
{
byte **ppb = (byte*) ppv;
byte* pbResize;
pbResize = (byte*)realloc(*ppb, sizeNew);
if( pbResize != NULL)
*ppb = pbResize;
return(pbResize != NULL)
}

if the function fails, pbBuf is not filled with NULL and it still points to former memory block.

Overflow problem:
char chToLower[UCHAR_MAX+1];
void BuildToLowerTable(void)
{
unsinged char ch;
for ( ch=0; ch <= UCHAR_MAX; ch++ ) chToLower[ch] = ch; ... }

when ch equals to CHAR_MAX, it looks it is the last iteration of the loop. But ch is change to CHAR_MAX+1 and this makes ch overflow to 0. So ch is less than UCHAR_MAX forever.
memchr()-find character in memory block, what's the problem with following codes:
void *memchr( void *pv, unsigned char ch, size_t size)
{
unsigned char *pch = (unsigned char *)pv;
unsigned char *pchEnd = pch + size;
while( pch < pch ="=">
when pv points to the last 72 bytes of the memory blocks and 'size' is also 72, then the above codes will search forever. The following codes are usually dangerous:
pchEnd = pch + size;
while(pch <>
well, how about using:
pchEnd = pch + size -1;
while ( pch<= pchEnd) ... Still wrong. Now pchEnd points to a legal location, but every time pch reaches pchEnd+1, overflow happens and the loop will never stop.
void *memchr( void *pv, unsigned char ch, size_t size)
{
unsigned char *pch = (unsigned char *)pv;
while( size-- > 0)
{
if (*pch == ch )
return(pch);
pch++;
}
return(NULL);
}

This code are good one. How about using '(--size >= 0)' to replace '(size-- > 0)'? It doesn't work because:
if size is an unsigned value, it is always greater than 0 and the loop will keep running.
if size is a signed value, it still doesn't work: if size is 'int' and enters the loop with the mimimum negative value INT_MIN, it minus 1 first and overflow happens. The loop will get a big number for loop.

When the reported bug disappears, 3 reasons:
  1. The bug is reported wrong
  2. The bug is solved by other programmers
  3. The bug is still there but just doesn't show up.
So you have to know why the bug disappears.

Spend some time to find the correct way to solve the problem. Don't use a lot of time to 'try'


No comments:

Post a Comment