Heap improvements (#462)

* Heap improvements

This commit makes the following improvements:

1. Add a check to heap_2 to track if a memory block is allocated to the
   application or not. The MSB of the size field is used for this
   purpose. The same check already exists in heap_4 and heap_5. This
   check prevents against double free.

2. Add a new flag configHEAP_CLEAR_MEMORY_ON_FREE to heap_2, heap_4 and
   heap_5. The application writer can set it to 1 in their
   FreeRTOSConfig.h to ensure that a block of memory allocated using
   pvPortMalloc is cleared (i.e. set to zero) when it is freed using
   vPortFree. If left undefined, configHEAP_CLEAR_MEMORY_ON_FREE
   defaults to 0 for backward compatibility. We recommend setting
   configHEAP_CLEAR_MEMORY_ON_FREE to 1 for better security.

3. Add a new API pvPortCalloc to heap_2, heap_4 and heap_5. This API
   has the following signature:
   void * pvPortCalloc( size_t xNum, size_t xSize );
   It allocates memory for an array of xNum objects each of which is of
   xSize and initializes all bytes in the allocated storage to zero. If
   allocation succeeds, it returns a pointer to the lowest byte in the
   allocated memory block. On failure, it returns a null pointer.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
diff --git a/include/portable.h b/include/portable.h
index 22bb9b0..0feedad 100644
--- a/include/portable.h
+++ b/include/portable.h
@@ -173,6 +173,8 @@
  * Map to the memory management routines required for the port.

  */

 void * pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;

+void * pvPortCalloc( size_t xNum,

+                     size_t xSize ) PRIVILEGED_FUNCTION;

 void vPortFree( void * pv ) PRIVILEGED_FUNCTION;

 void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;

 size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;

diff --git a/portable/MemMang/heap_2.c b/portable/MemMang/heap_2.c
index 4974f14..85ebdf2 100644
--- a/portable/MemMang/heap_2.c
+++ b/portable/MemMang/heap_2.c
@@ -36,6 +36,7 @@
  * memory management pages of https://www.FreeRTOS.org for more information.

  */

 #include <stdlib.h>

+#include <string.h>

 

 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining

  * all the API functions to use the MPU wrappers.  That should only be done when

@@ -51,13 +52,30 @@
     #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0

 #endif

 

+#ifndef configHEAP_CLEAR_MEMORY_ON_FREE

+    #define configHEAP_CLEAR_MEMORY_ON_FREE    0

+#endif

+

 /* A few bytes might be lost to byte aligning the heap start address. */

 #define configADJUSTED_HEAP_SIZE    ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )

 

-/*

- * Initialises the heap structures before their first use.

- */

-static void prvHeapInit( void );

+/* Assumes 8bit bytes! */

+#define heapBITS_PER_BYTE           ( ( size_t ) 8 )

+

+/* Check if multiplying a and b will result in overflow. */

+#define heapMULTIPLY_WILL_OVERFLOW( a, b, max )    ( ( ( a ) > 0 ) && ( ( b ) > ( ( max ) / ( a ) ) ) )

+

+/* MSB of the xBlockSize member of an BlockLink_t structure is used to track

+ * the allocation status of a block.  When MSB of the xBlockSize member of

+ * an BlockLink_t structure is set then the block belongs to the application.

+ * When the bit is free the block is still part of the free heap space. */

+#define heapBLOCK_ALLOCATED_BITMASK    ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )

+#define heapBLOCK_SIZE_IS_VALID( xBlockSize )    ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )

+#define heapBLOCK_IS_ALLOCATED( pxBlock )        ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )

+#define heapALLOCATE_BLOCK( pxBlock )            ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )

+#define heapFREE_BLOCK( pxBlock )                ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )

+

+/*-----------------------------------------------------------*/

 

 /* Allocate the memory for the heap. */

 #if ( configAPPLICATION_ALLOCATED_HEAP == 1 )

@@ -66,7 +84,7 @@
 * heap - probably so it can be placed in a special segment or address. */

     extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

 #else

-    static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

+    PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

 #endif /* configAPPLICATION_ALLOCATED_HEAP */

 

 

@@ -83,11 +101,20 @@
 #define heapMINIMUM_BLOCK_SIZE    ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )

 

 /* Create a couple of list links to mark the start and end of the list. */

-static BlockLink_t xStart, xEnd;

+PRIVILEGED_DATA static BlockLink_t xStart, xEnd;

 

 /* Keeps track of the number of free bytes remaining, but says nothing about

  * fragmentation. */

-static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;

+PRIVILEGED_DATA static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;

+

+/*-----------------------------------------------------------*/

+

+/*

+ * Initialises the heap structures before their first use.

+ */

+static void prvHeapInit( void ) PRIVILEGED_FUNCTION;

+

+/*-----------------------------------------------------------*/

 

 /* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */

 

@@ -120,7 +147,7 @@
 void * pvPortMalloc( size_t xWantedSize )

 {

     BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;

-    static BaseType_t xHeapHasBeenInitialised = pdFALSE;

+    PRIVILEGED_DATA static BaseType_t xHeapHasBeenInitialised = pdFALSE;

     void * pvReturn = NULL;

 

     vTaskSuspendAll();

@@ -133,72 +160,84 @@
             xHeapHasBeenInitialised = pdTRUE;

         }

 

-        /* The wanted size must be increased so it can contain a BlockLink_t

-         * structure in addition to the requested amount of bytes. */

-        if( ( xWantedSize > 0 ) &&

-            ( ( xWantedSize + heapSTRUCT_SIZE ) > xWantedSize ) ) /* Overflow check */

+        /* Check the requested block size is not so large that the top bit is

+         * set.  The top bit of the block size member of the BlockLink_t structure

+         * is used to determine who owns the block - the application or the

+         * kernel, so it must be free. */

+        if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) )

         {

-            xWantedSize += heapSTRUCT_SIZE;

-

-            /* Byte alignment required. Check for overflow. */

-            if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) )

-                > xWantedSize )

+            /* The wanted size must be increased so it can contain a BlockLink_t

+             * structure in addition to the requested amount of bytes. */

+            if( ( xWantedSize > 0 ) &&

+                ( ( xWantedSize + heapSTRUCT_SIZE ) > xWantedSize ) ) /* Overflow check */

             {

-                xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );

-                configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );

+                xWantedSize += heapSTRUCT_SIZE;

+

+                /* Byte alignment required. Check for overflow. */

+                if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) )

+                    > xWantedSize )

+                {

+                    xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );

+                    configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );

+                }

+                else

+                {

+                    xWantedSize = 0;

+                }

             }

             else

             {

                 xWantedSize = 0;

             }

-        }

-        else

-        {

-            xWantedSize = 0;

-        }

 

-        if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )

-        {

-            /* Blocks are stored in byte order - traverse the list from the start

-             * (smallest) block until one of adequate size is found. */

-            pxPreviousBlock = &xStart;

-            pxBlock = xStart.pxNextFreeBlock;

-

-            while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )

+            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )

             {

-                pxPreviousBlock = pxBlock;

-                pxBlock = pxBlock->pxNextFreeBlock;

-            }

+                /* Blocks are stored in byte order - traverse the list from the start

+                 * (smallest) block until one of adequate size is found. */

+                pxPreviousBlock = &xStart;

+                pxBlock = xStart.pxNextFreeBlock;

 

-            /* If we found the end marker then a block of adequate size was not found. */

-            if( pxBlock != &xEnd )

-            {

-                /* Return the memory space - jumping over the BlockLink_t structure

-                 * at its start. */

-                pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );

-

-                /* This block is being returned for use so must be taken out of the

-                 * list of free blocks. */

-                pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

-

-                /* If the block is larger than required it can be split into two. */

-                if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )

+                while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )

                 {

-                    /* This block is to be split into two.  Create a new block

-                     * following the number of bytes requested. The void cast is

-                     * used to prevent byte alignment warnings from the compiler. */

-                    pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

-

-                    /* Calculate the sizes of two blocks split from the single

-                     * block. */

-                    pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;

-                    pxBlock->xBlockSize = xWantedSize;

-

-                    /* Insert the new block into the list of free blocks. */

-                    prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );

+                    pxPreviousBlock = pxBlock;

+                    pxBlock = pxBlock->pxNextFreeBlock;

                 }

 

-                xFreeBytesRemaining -= pxBlock->xBlockSize;

+                /* If we found the end marker then a block of adequate size was not found. */

+                if( pxBlock != &xEnd )

+                {

+                    /* Return the memory space - jumping over the BlockLink_t structure

+                     * at its start. */

+                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );

+

+                    /* This block is being returned for use so must be taken out of the

+                     * list of free blocks. */

+                    pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

+

+                    /* If the block is larger than required it can be split into two. */

+                    if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )

+                    {

+                        /* This block is to be split into two.  Create a new block

+                         * following the number of bytes requested. The void cast is

+                         * used to prevent byte alignment warnings from the compiler. */

+                        pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

+

+                        /* Calculate the sizes of two blocks split from the single

+                         * block. */

+                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;

+                        pxBlock->xBlockSize = xWantedSize;

+

+                        /* Insert the new block into the list of free blocks. */

+                        prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );

+                    }

+

+                    xFreeBytesRemaining -= pxBlock->xBlockSize;

+

+                    /* The block is being returned - it is allocated and owned

+                     * by the application and has no "next" block. */

+                    heapALLOCATE_BLOCK( pxBlock );

+                    pxBlock->pxNextFreeBlock = NULL;

+                }

             }

         }

 

@@ -235,14 +274,32 @@
          * byte alignment warnings. */

         pxLink = ( void * ) puc;

 

-        vTaskSuspendAll();

+        configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) );

+        configASSERT( pxLink->pxNextFreeBlock == NULL );

+

+        if( heapBLOCK_IS_ALLOCATED( pxLink ) )

         {

-            /* Add this block to the list of free blocks. */

-            prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );

-            xFreeBytesRemaining += pxLink->xBlockSize;

-            traceFREE( pv, pxLink->xBlockSize );

+            if( pxLink->pxNextFreeBlock == NULL )

+            {

+                /* The block is being returned to the heap - it is no longer

+                 * allocated. */

+                heapFREE_BLOCK( pxLink );

+                #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )

+                {

+                    ( void ) memset( puc + heapSTRUCT_SIZE, 0, pxLink->xBlockSize - heapSTRUCT_SIZE );

+                }

+                #endif

+

+                vTaskSuspendAll();

+                {

+                    /* Add this block to the list of free blocks. */

+                    prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );

+                    xFreeBytesRemaining += pxLink->xBlockSize;

+                    traceFREE( pv, pxLink->xBlockSize );

+                }

+                ( void ) xTaskResumeAll();

+            }

         }

-        ( void ) xTaskResumeAll();

     }

 }

 /*-----------------------------------------------------------*/

@@ -259,7 +316,27 @@
 }

 /*-----------------------------------------------------------*/

 

-static void prvHeapInit( void )

+void * pvPortCalloc( size_t xNum,

+                     size_t xSize )

+{

+    void * pv = NULL;

+    const size_t xSizeMaxValue = ~( ( size_t ) 0 );

+

+    if( !heapMULTIPLY_WILL_OVERFLOW( xNum, xSize, xSizeMaxValue ) )

+    {

+        pv = pvPortMalloc( xNum * xSize );

+

+        if( pv != NULL )

+        {

+            ( void ) memset( pv, 0, xNum * xSize );

+        }

+    }

+

+    return pv;

+}

+/*-----------------------------------------------------------*/

+

+static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */

 {

     BlockLink_t * pxFirstFreeBlock;

     uint8_t * pucAlignedHeap;

diff --git a/portable/MemMang/heap_4.c b/portable/MemMang/heap_4.c
index 79f6666..2ef5381 100644
--- a/portable/MemMang/heap_4.c
+++ b/portable/MemMang/heap_4.c
@@ -35,6 +35,7 @@
  * memory management pages of https://www.FreeRTOS.org for more information.

  */

 #include <stdlib.h>

+#include <string.h>

 

 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining

  * all the API functions to use the MPU wrappers.  That should only be done when

@@ -50,12 +51,31 @@
     #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0

 #endif

 

+#ifndef configHEAP_CLEAR_MEMORY_ON_FREE

+    #define configHEAP_CLEAR_MEMORY_ON_FREE    0

+#endif

+

 /* Block sizes must not get too small. */

 #define heapMINIMUM_BLOCK_SIZE    ( ( size_t ) ( xHeapStructSize << 1 ) )

 

 /* Assumes 8bit bytes! */

 #define heapBITS_PER_BYTE         ( ( size_t ) 8 )

 

+/* Check if multiplying a and b will result in overflow. */

+#define heapMULTIPLY_WILL_OVERFLOW( a, b, max )    ( ( ( a ) > 0 ) && ( ( b ) > ( ( max ) / ( a ) ) ) )

+

+/* MSB of the xBlockSize member of an BlockLink_t structure is used to track

+ * the allocation status of a block.  When MSB of the xBlockSize member of

+ * an BlockLink_t structure is set then the block belongs to the application.

+ * When the bit is free the block is still part of the free heap space. */

+#define heapBLOCK_ALLOCATED_BITMASK    ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )

+#define heapBLOCK_SIZE_IS_VALID( xBlockSize )    ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )

+#define heapBLOCK_IS_ALLOCATED( pxBlock )        ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )

+#define heapALLOCATE_BLOCK( pxBlock )            ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )

+#define heapFREE_BLOCK( pxBlock )                ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )

+

+/*-----------------------------------------------------------*/

+

 /* Allocate the memory for the heap. */

 #if ( configAPPLICATION_ALLOCATED_HEAP == 1 )

 

@@ -106,12 +126,6 @@
 PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = 0;

 PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = 0;

 

-/* Gets set to the top bit of an size_t type.  When this bit in the xBlockSize

- * member of an BlockLink_t structure is set then the block belongs to the

- * application.  When the bit is free the block is still part of the free heap

- * space. */

-PRIVILEGED_DATA static size_t xBlockAllocatedBit = 0;

-

 /*-----------------------------------------------------------*/

 

 void * pvPortMalloc( size_t xWantedSize )

@@ -136,7 +150,7 @@
          * set.  The top bit of the block size member of the BlockLink_t structure

          * is used to determine who owns the block - the application or the

          * kernel, so it must be free. */

-        if( ( xWantedSize & xBlockAllocatedBit ) == 0 )

+        if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) )

         {

             /* The wanted size must be increased so it can contain a BlockLink_t

              * structure in addition to the requested amount of bytes. */

@@ -232,7 +246,7 @@
 

                     /* The block is being returned - it is allocated and owned

                      * by the application and has no "next" block. */

-                    pxBlock->xBlockSize |= xBlockAllocatedBit;

+                    heapALLOCATE_BLOCK( pxBlock );

                     pxBlock->pxNextFreeBlock = NULL;

                     xNumberOfSuccessfulAllocations++;

                 }

@@ -288,17 +302,21 @@
         /* This casting is to keep the compiler from issuing warnings. */

         pxLink = ( void * ) puc;

 

-        /* Check the block is actually allocated. */

-        configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );

+        configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) );

         configASSERT( pxLink->pxNextFreeBlock == NULL );

 

-        if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )

+        if( heapBLOCK_IS_ALLOCATED( pxLink ) )

         {

             if( pxLink->pxNextFreeBlock == NULL )

             {

                 /* The block is being returned to the heap - it is no longer

                  * allocated. */

-                pxLink->xBlockSize &= ~xBlockAllocatedBit;

+                heapFREE_BLOCK( pxLink );

+                #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )

+                {

+                    ( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );

+                }

+                #endif

 

                 vTaskSuspendAll();

                 {

@@ -341,6 +359,26 @@
 }

 /*-----------------------------------------------------------*/

 

+void * pvPortCalloc( size_t xNum,

+                     size_t xSize )

+{

+    void * pv = NULL;

+    const size_t xSizeMaxValue = ~( ( size_t ) 0 );

+

+    if( !heapMULTIPLY_WILL_OVERFLOW( xNum, xSize, xSizeMaxValue ) )

+    {

+        pv = pvPortMalloc( xNum * xSize );

+

+        if( pv != NULL )

+        {

+            ( void ) memset( pv, 0, xNum * xSize );

+        }

+    }

+

+    return pv;

+}

+/*-----------------------------------------------------------*/

+

 static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */

 {

     BlockLink_t * pxFirstFreeBlock;

@@ -383,9 +421,6 @@
     /* Only one block exists - and it covers the entire usable heap space. */

     xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;

     xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;

-

-    /* Work out the position of the top bit in a size_t variable. */

-    xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );

 }

 /*-----------------------------------------------------------*/

 

@@ -502,3 +537,4 @@
     }

     taskEXIT_CRITICAL();

 }

+/*-----------------------------------------------------------*/

diff --git a/portable/MemMang/heap_5.c b/portable/MemMang/heap_5.c
index c0d92ed..c12c956 100644
--- a/portable/MemMang/heap_5.c
+++ b/portable/MemMang/heap_5.c
@@ -69,6 +69,7 @@
  *

  */

 #include <stdlib.h>

+#include <string.h>

 

 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining

  * all the API functions to use the MPU wrappers.  That should only be done when

@@ -84,12 +85,31 @@
     #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0

 #endif

 

+#ifndef configHEAP_CLEAR_MEMORY_ON_FREE

+    #define configHEAP_CLEAR_MEMORY_ON_FREE    0

+#endif

+

 /* Block sizes must not get too small. */

 #define heapMINIMUM_BLOCK_SIZE    ( ( size_t ) ( xHeapStructSize << 1 ) )

 

 /* Assumes 8bit bytes! */

 #define heapBITS_PER_BYTE         ( ( size_t ) 8 )

 

+/* Check if multiplying a and b will result in overflow. */

+#define heapMULTIPLY_WILL_OVERFLOW( a, b, max )    ( ( ( a ) > 0 ) && ( ( b ) > ( ( max ) / ( a ) ) ) )

+

+/* MSB of the xBlockSize member of an BlockLink_t structure is used to track

+ * the allocation status of a block.  When MSB of the xBlockSize member of

+ * an BlockLink_t structure is set then the block belongs to the application.

+ * When the bit is free the block is still part of the free heap space. */

+#define heapBLOCK_ALLOCATED_BITMASK    ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )

+#define heapBLOCK_SIZE_IS_VALID( xBlockSize )    ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )

+#define heapBLOCK_IS_ALLOCATED( pxBlock )        ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )

+#define heapALLOCATE_BLOCK( pxBlock )            ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )

+#define heapFREE_BLOCK( pxBlock )                ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )

+

+/*-----------------------------------------------------------*/

+

 /* Define the linked list structure.  This is used to link free blocks in order

  * of their memory address. */

 typedef struct A_BLOCK_LINK

@@ -124,12 +144,6 @@
 static size_t xNumberOfSuccessfulAllocations = 0;

 static size_t xNumberOfSuccessfulFrees = 0;

 

-/* Gets set to the top bit of an size_t type.  When this bit in the xBlockSize

- * member of an BlockLink_t structure is set then the block belongs to the

- * application.  When the bit is free the block is still part of the free heap

- * space. */

-static size_t xBlockAllocatedBit = 0;

-

 /*-----------------------------------------------------------*/

 

 void * pvPortMalloc( size_t xWantedSize )

@@ -147,7 +161,7 @@
          * set.  The top bit of the block size member of the BlockLink_t structure

          * is used to determine who owns the block - the application or the

          * kernel, so it must be free. */

-        if( ( xWantedSize & xBlockAllocatedBit ) == 0 )

+        if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) )

         {

             /* The wanted size is increased so it can contain a BlockLink_t

              * structure in addition to the requested amount of bytes. */

@@ -241,7 +255,7 @@
 

                     /* The block is being returned - it is allocated and owned

                      * by the application and has no "next" block. */

-                    pxBlock->xBlockSize |= xBlockAllocatedBit;

+                    heapALLOCATE_BLOCK( pxBlock );

                     pxBlock->pxNextFreeBlock = NULL;

                     xNumberOfSuccessfulAllocations++;

                 }

@@ -296,17 +310,21 @@
         /* This casting is to keep the compiler from issuing warnings. */

         pxLink = ( void * ) puc;

 

-        /* Check the block is actually allocated. */

-        configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );

+        configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) );

         configASSERT( pxLink->pxNextFreeBlock == NULL );

 

-        if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )

+        if( heapBLOCK_IS_ALLOCATED( pxLink ) )

         {

             if( pxLink->pxNextFreeBlock == NULL )

             {

                 /* The block is being returned to the heap - it is no longer

                  * allocated. */

-                pxLink->xBlockSize &= ~xBlockAllocatedBit;

+                heapFREE_BLOCK( pxLink );

+                #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )

+                {

+                    ( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );

+                }

+                #endif

 

                 vTaskSuspendAll();

                 {

@@ -343,6 +361,26 @@
 }

 /*-----------------------------------------------------------*/

 

+void * pvPortCalloc( size_t xNum,

+                     size_t xSize )

+{

+    void * pv = NULL;

+    const size_t xSizeMaxValue = ~( ( size_t ) 0 );

+

+    if( !heapMULTIPLY_WILL_OVERFLOW( xNum, xSize, xSizeMaxValue ) )

+    {

+        pv = pvPortMalloc( xNum * xSize );

+

+        if( pv != NULL )

+        {

+            ( void ) memset( pv, 0, xNum * xSize );

+        }

+    }

+

+    return pv;

+}

+/*-----------------------------------------------------------*/

+

 static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert )

 {

     BlockLink_t * pxIterator;

@@ -495,9 +533,6 @@
 

     /* Check something was actually defined before it is accessed. */

     configASSERT( xTotalHeapSize );

-

-    /* Work out the position of the top bit in a size_t variable. */

-    xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );

 }

 /*-----------------------------------------------------------*/

 

@@ -557,3 +592,4 @@
     }

     taskEXIT_CRITICAL();

 }

+/*-----------------------------------------------------------*/