1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
37
38
39
40
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
80
81
82
83
84
85
86
87
88
89
90
94
95
96
97
98
100
101
105
106
110
111
112
117
118
119
120
121
122
126
127
128
131
132
133
134
137
138
139
140
146
147
148
152
153
154
155
156
158
159
160
161
162
163
164
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
186
187
188
189
190
192
193
194
195
196
197
201
205
206
210
211
215
216
220
221
222
223
225
229
233
234
238
239
240
241
242
244
245
246
247
248
254
255
257
258
259
261
262
263
264
266
267
268
270
271
272
273
274
278
279
280
281
283
284
285
286
287
288
289
290
294
295
296
297
301
305
306
307
308
310
311
312
313
314
318
319
323
324
328
329
330
331
332
333
334
335
336
337
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
363
364
365
366
367
368
369
370
371
372
373
374
375
376
378
379
380
388
389
390
391
398
399
400
404
405
409
410
411
412
413
417
418
419
423
424
425
429
430
431
432
433
434
435
436
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
465
466
467
470
471
472
474
475
476
477
479
480
481
482
483
484
485
486
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
505
509
510
514
515
517
518
519
524
528
529
531
532
533
546
550
551
555
559
563
564
565
566
567
568
569
570
571
572
573
574
575
577
578
579
580
581
583
584
585
589
590
594
595
597
598
599
600
601
602
603
604
605
606
607
608
614
615
616
617
618
623
624
625
626
627
628
629
630
631
632
/* ... */
/* ... */
#include <stdlib.h>
#include <string.h>
/* ... */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#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
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
#define heapSUBTRACT_WILL_UNDERFLOW( a, b ) ( ( a ) < ( b ) )
/* ... */
#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 )
11 defines
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* ... */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];/* ... */
#else
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif
/* ... */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK * pxNextFreeBlock;
size_t xBlockSize;
...} BlockLink_t;
/* ... */
#if ( configENABLE_HEAP_PROTECTOR == 1 )
/* ... */
extern void vApplicationGetRandomHeapCanary( portPOINTER_SIZE_TYPE * pxHeapCanary );
PRIVILEGED_DATA static portPOINTER_SIZE_TYPE xHeapCanary;
/* ... */
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( ( BlockLink_t * ) ( ( ( portPOINTER_SIZE_TYPE ) ( pxBlock ) ) ^ xHeapCanary ) )
/* ... */#else
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( pxBlock )
/* ... */
#endif
#define heapVALIDATE_BLOCK_POINTER( pxBlock ) \
configASSERT( ( ( uint8_t * ) ( pxBlock ) >= &( ucHeap[ 0 ] ) ) && \
( ( uint8_t * ) ( pxBlock ) <= &( ucHeap[ configTOTAL_HEAP_SIZE - 1 ] ) ) )...
/* ... */
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
/* ... */
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
/* ... */
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
PRIVILEGED_DATA static BlockLink_t xStart;
PRIVILEGED_DATA static BlockLink_t * pxEnd = NULL;
/* ... */
PRIVILEGED_DATA static size_t xFreeBytesRemaining = ( size_t ) 0U;
PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = ( size_t ) 0U;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = ( size_t ) 0U;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = ( size_t ) 0U;
void * pvPortMalloc( size_t xWantedSize )
{
BlockLink_t * pxBlock;
BlockLink_t * pxPreviousBlock;
BlockLink_t * pxNewBlockLink;
void * pvReturn = NULL;
size_t xAdditionalRequiredSize;
size_t xAllocatedBlockSize = 0;
if( xWantedSize > 0 )
{
/* ... */
if( heapADD_WILL_OVERFLOW( xWantedSize, xHeapStructSize ) == 0 )
{
xWantedSize += xHeapStructSize;
/* ... */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );
if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
{
xWantedSize += xAdditionalRequiredSize;
}if (heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0) { ... }
else
{
xWantedSize = 0;
}else { ... }
}if (( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
}if (heapADD_WILL_OVERFLOW( xWantedSize, xHeapStructSize ) == 0) { ... }
else
{
xWantedSize = 0;
}else { ... }
}if (xWantedSize > 0) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
vTaskSuspendAll();
{
/* ... */
if( pxEnd == NULL )
{
prvHeapInit();
}if (pxEnd == NULL) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
/* ... */
if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
{
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* ... */
pxPreviousBlock = &xStart;
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
{
pxPreviousBlock = pxBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
}while (( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) )) { ... }
/* ... */
if( pxBlock != pxEnd )
{
/* ... */
pvReturn = ( void * ) ( ( ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock ) ) + xHeapStructSize );
heapVALIDATE_BLOCK_POINTER( pvReturn );
/* ... */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* ... */
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( pxBlock->xBlockSize, xWantedSize ) == 0 );
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* ... */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* ... */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
pxNewBlockLink->pxNextFreeBlock = pxPreviousBlock->pxNextFreeBlock;
pxPreviousBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxNewBlockLink );
}if (( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}if (xFreeBytesRemaining < xMinimumEverFreeBytesRemaining) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
xAllocatedBlockSize = pxBlock->xBlockSize;
/* ... */
heapALLOCATE_BLOCK( pxBlock );
pxBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );
xNumberOfSuccessfulAllocations++;
}if (pxBlock != pxEnd) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
}if (( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining )) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
}if (heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
traceMALLOC( pvReturn, xAllocatedBlockSize );
( void ) xAllocatedBlockSize;
...}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
vApplicationMallocFailedHook();
}if (pvReturn == NULL) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
...}/* ... */
#endif
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}{ ... }
void vPortFree( void * pv )
{
uint8_t * puc = ( uint8_t * ) pv;
BlockLink_t * pxLink;
if( pv != NULL )
{
/* ... */
puc -= xHeapStructSize;
pxLink = ( void * ) puc;
heapVALIDATE_BLOCK_POINTER( pxLink );
configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( NULL ) );
if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
{
if( pxLink->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( NULL ) )
{
/* ... */
heapFREE_BLOCK( pxLink );
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
{
/* ... */
if( heapSUBTRACT_WILL_UNDERFLOW( pxLink->xBlockSize, xHeapStructSize ) == 0 )
{
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
}if (heapSUBTRACT_WILL_UNDERFLOW( pxLink->xBlockSize, xHeapStructSize ) == 0) { ... }
...}/* ... */
#endif
vTaskSuspendAll();
{
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xNumberOfSuccessfulFrees++;
...}
( void ) xTaskResumeAll();
}if (pxLink->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( NULL )) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
}if (heapBLOCK_IS_ALLOCATED( pxLink ) != 0) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
}if (pv != NULL) { ... }
}{ ... }
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}{ ... }
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}{ ... }
void vPortInitialiseBlocks( void )
{
}{ ... }
void * pvPortCalloc( size_t xNum,
size_t xSize )
{
void * pv = NULL;
if( heapMULTIPLY_WILL_OVERFLOW( xNum, xSize ) == 0 )
{
pv = pvPortMalloc( xNum * xSize );
if( pv != NULL )
{
( void ) memset( pv, 0, xNum * xSize );
}if (pv != NULL) { ... }
}if (heapMULTIPLY_WILL_OVERFLOW( xNum, xSize ) == 0) { ... }
return pv;
}{ ... }
static void prvHeapInit( void )
{
BlockLink_t * pxFirstFreeBlock;
portPOINTER_SIZE_TYPE uxStartAddress, uxEndAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
uxStartAddress = ( portPOINTER_SIZE_TYPE ) ucHeap;
if( ( uxStartAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxStartAddress += ( portBYTE_ALIGNMENT - 1 );
uxStartAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= ( size_t ) ( uxStartAddress - ( portPOINTER_SIZE_TYPE ) ucHeap );
}if (( uxStartAddress & portBYTE_ALIGNMENT_MASK ) != 0) { ... }
#if ( configENABLE_HEAP_PROTECTOR == 1 )
{
vApplicationGetRandomHeapCanary( &( xHeapCanary ) );
...}/* ... */
#endif
/* ... */
xStart.pxNextFreeBlock = ( void * ) heapPROTECT_BLOCK_POINTER( uxStartAddress );
xStart.xBlockSize = ( size_t ) 0;
/* ... */
uxEndAddress = uxStartAddress + ( portPOINTER_SIZE_TYPE ) xTotalHeapSize;
uxEndAddress -= ( portPOINTER_SIZE_TYPE ) xHeapStructSize;
uxEndAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( BlockLink_t * ) uxEndAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );
/* ... */
pxFirstFreeBlock = ( BlockLink_t * ) uxStartAddress;
pxFirstFreeBlock->xBlockSize = ( size_t ) ( uxEndAddress - ( portPOINTER_SIZE_TYPE ) pxFirstFreeBlock );
pxFirstFreeBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
...}
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert )
{
BlockLink_t * pxIterator;
uint8_t * puc;
/* ... */
for( pxIterator = &xStart; heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) < pxBlockToInsert; pxIterator = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
}for (pxIterator = &xStart; heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) < pxBlockToInsert; pxIterator = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )) { ... }
if( pxIterator != &xStart )
{
heapVALIDATE_BLOCK_POINTER( pxIterator );
}if (pxIterator != &xStart) { ... }
/* ... */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}if (( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
/* ... */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
if( heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) != pxEnd )
{
pxBlockToInsert->xBlockSize += heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->pxNextFreeBlock;
}if (heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) != pxEnd) { ... }
else
{
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
}else { ... }
}if (( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )) { ... }
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}else { ... }
/* ... */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxBlockToInsert );
}if (pxIterator != pxBlockToInsert) { ... }
else
{
mtCOVERAGE_TEST_MARKER();
}else { ... }
...}
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
{
BlockLink_t * pxBlock;
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY;
vTaskSuspendAll();
{
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
/* ... */
if( pxBlock != NULL )
{
while( pxBlock != pxEnd )
{
/* ... */
xBlocks++;
if( pxBlock->xBlockSize > xMaxSize )
{
xMaxSize = pxBlock->xBlockSize;
}if (pxBlock->xBlockSize > xMaxSize) { ... }
if( pxBlock->xBlockSize < xMinSize )
{
xMinSize = pxBlock->xBlockSize;
}if (pxBlock->xBlockSize < xMinSize) { ... }
/* ... */
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
}while (pxBlock != pxEnd) { ... }
}if (pxBlock != NULL) { ... }
...}
( void ) xTaskResumeAll();
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
taskENTER_CRITICAL();
{
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
...}
taskEXIT_CRITICAL();
}{ ... }
/* ... */
void vPortHeapResetState( void )
{
pxEnd = NULL;
xFreeBytesRemaining = ( size_t ) 0U;
xMinimumEverFreeBytesRemaining = ( size_t ) 0U;
xNumberOfSuccessfulAllocations = ( size_t ) 0U;
xNumberOfSuccessfulFrees = ( size_t ) 0U;
}{ ... }