The following is designed to take a variable length constant char and print it out in a nice format for logging. I am certain readers will have suggestions on how this can be improved, and I’d welcome it.
What puzzles me is that I expected it would be necessary to free() the returned static char each time ToHexString() is called. Instead, I see no memory leak whatsoever. Even tho I use the function inline and therefore do not assign its return value to a variable.
I created a simple test that calls this function in a loop, each time with a different length cString and nMaxChars parameter. Then I watched VM status. The memory allocation for my test program, and free memory, never changed.
It seems to me it should have increased each time a malloc is called and no free.
static char *ToHexString(const char *cString,int nMaxChars)
{
static char *cStr;
/*if (80>strlen(cString))
nRawChars=strlen(cString);
if (nMaxChars>nRawChars)
nRawChars=nMaxChars;
*/
if (nMaxChars==0)
nMaxChars=80;
printf("There are %i chars\n",nMaxChars);
char *cStr1;
char *cStr2;
char *cStr3;
int nLen=nMaxChars*6;
cStr=calloc(nLen,sizeof(char));
cStr1=calloc(10,sizeof(char));
cStr2=calloc(nLen,sizeof(char));
cStr3=calloc(nLen,sizeof(char));
cStr1[0]='\0';
cStr2[0]='\0';
cStr3[0]='\0';
int nC1=0;
int nRowCnt=0;
for (nC1=0;nC1<nMaxChars;nC1++)
{
++nRowCnt;
if (cString[nC1]==0x00)
snprintf(cStr1,8,"[00] ");
else
snprintf(cStr1,8,"[%02x] ",(unsigned char)cString[nC1]);
if ( (nRowCnt%8==0) )
{
snprintf(cStr3,nLen,"%s%s\n",cStr2,cStr1);
}
else
snprintf(cStr3,nLen,"%s%s",cStr2,cStr1);
snprintf(cStr2,nLen,"%s",cStr3);
}
snprintf(cStr,nLen,"%s",cStr3);
free(cStr1);
free(cStr2);
free(cStr3);
return(cStr);
}
Here is the calling routine:
for (i=0;i<100;i++)
{
memset(&cBuff, 0,255);
printf("Reading %s now..\n",cPort);
while (sleep(1)==-1);
nChars=read(nPort, cBuff, 255);
//printf("Read %i chars from %s\n",nChars,cPort);
if (nChars<=0)
printf("Read 0 chars from %s\n",cPort);
else
printf("Read %i chars from %s\n%s\n",nChars,cPort,ToHexString(cBuff,nChars));
}
The following is a leak:
Valgrind output:
Note,
still reachable(1024 bytes) is the result of the last timememeat()was entered. The static pointer still held a valid reference to the last blockmemeat()allocated when the program exited. Just not the previous blocks.The following is NOT a leak:
Valgrind output:
Here, the address
foopointed to has been freed, andfoonow points to the newly allocated address, and will continue to do so the next timememeat()is entered.Explanation:
The
staticstorage type says that the pointerfoowill point to the same address as initialized each time the function is entered. However, if you change that address each time the function is entered viamalloc()orcalloc(), you’ve lost the reference to the blocks from the previous allocation. Hence, a leak, since either is going to return a new address.‘Still Reachable’ in valgrind means that that all allocated heap blocks still have a valid pointer to access / manipulate / free them upon exit. This is similar to allocating memory in
main()and not freeing it, just relying on the OS to reclaim memory.In short, yes – you have a leak. However, you can fix it rather easily. Just note that you are indeed relying on your OS to reclaim the memory unless you add another argument to your function that just tells
ToHexStringto call free on the static pointer, which you could use when exiting.Similar to this: (full test program)
Valgrind output:
Note on the final output:
Yes, 6144 bytes were actually allocated according to what
malloc()returned while the program ran, but that just means the static pointer was freed, then reallocated according to the number of timesmemeat()was entered. The actual heap use of the program at any given time was actually just 2*1024, 1k to allocate the new pointer while the old one still existed waiting to be copied to the new one.Again, it should not be too hard to adjust your code, but it isn’t clear to me why you are using static storage to begin with.