Minor issue with heap_2.c

dharper08 wrote on Tuesday, July 20, 2010:

Version: v6.0.4 (although the issue exists in v6.0.5 also)

I am using FreeRTOS along with lwIP (v1.3.0) on an Atmel AT91SAM7X512 based board in a project that implements a web server based user interface.  I had been having some problems with a memory leak and I embedded some debugging code to help track it down.  This turned out to be extremely fortunate as it not only helped me fix the bug in my code but it also showed another issue that I otherwise never would have seen.  One part of the code I added tracked the value of the variable xFreeBytesRemaining.  This is a variable that is unique to heap_2.c and, as the name suggests, it tracks the remaining amount of heap memory.  Obviously, it is decremented by the amount allocated in pvPortMalloc and incremented by the amount released in vPortFree. 

I had expected xFreeBytesRemaining to eventually reach a near equilibrium point after running a while.  I had a sequence in my browser window where I could press a “button” and the FreeRTOS code would perform a specific sequence, update the browser and return to the same state it was in before.  To my surprise, I found that the value of xFreeBytesRemaining was increasing by 0x10 bytes every time I pressed the button.  As near as I can tell, the problem occurs in the function pvPortMalloc in the heap_2.c file.  It appears that somewhere in the lwIP code, there is a malloc for a single byte.  The following description uses line numbers from v6.0.4 - version v6.0.5 is the same code but the line numbers are off by 2.

When pvPortMalloc is entered, the value of xWantedSize is 1.  On line 174 it is checked to verify that it is greater than 0 and, since it is, it is incremented by heapSTRUCT_SIZE.  This takes xWantedSize up to a value of 0x11.  Next the alignment is checked on line 179 and, since it is not a multiple of portBYTE_ALIGNMENT_MASK, it is further incremented up to a value of 0x18.  Line 186 checks that it is a legitimate value and less than configTOTAL_HEAP_SIZE.  Since it is, the code now searches the linked list looking for the smallest size block that will match the request.  It finds one in a block that has a pxBlock->xBlockSize value of 0x28.  Next, the block is checked to see if it needs to be split up into a section to be returned to the calling function and a remainder that is put back on the free chain.  In this case, line 207 checks to see if the current block size (pxBlock->xBlockSize) minus the requested amount (xWantedSize) is greater than the value of heapMINIMUM_BLOCK_SIZE.  In this case, they are equal so the block is not split (which it shouldn’t be, otherwise the section returned to the free chain would be the size of heapSTRUCT_SIZE which would render it useless from then on).  Since the split is not performed, pxBlock->xBlockSize remains at a value of 0x28.  However, on line 226, xFreeBytesRemaining is decremented by the value of xWantedSize which is still 0x18.  Eventually the memory is released through function vPortFree.  Here, on line 264, the value of xFreeBytesRemaining is incremented by the value of pxLink->xBlockSize which is still 0x28.  Thus, xFreeBytesRemaining increments by the difference of 0x10 bytes every time this sequence is performed. 

I believe the problem can be corrected on line 226 of pvPortMalloc by changing it to read:
   xFreeBytesRemaining -= pxBlock->xBlockSize.

As near as I can tell, this does not affect the operation of either pvPortMalloc or vPortFree, however, it would cause the xPortGetFreeHeapSize to return the wrong answer under the above situation.


rtel wrote on Tuesday, July 20, 2010:

Interesting.  Thanks for taking the time to write such a detailed and clear description.  I will take a look at it now!