Memory Profiling User Heap in C and C++

Memory Profiling for C and C++

When using Memory Profiling on embedded or real-time target platforms, you might encounter one of the following situations:

  • Situation 1: There are no provisions for malloc, calloc, realloc or free statements on the target platform.

Your application uses custom heap management routines that may use a user API. Such routines could, for example, be based on a static buffer that performs allocation and free actions.

In this case, you need to customize the memory heap parameters RTRT_DO_MALLOC and RTRT_DO_FREE in the TDP to use the custom malloc and free functions.

In this case, you can access the custom API functions.

  • Situation 2: There are partial implementations of malloc, calloc, realloc or free on the target, but other functions provide methods of allocating or freeing heap memory.

In this case, you do not have access to any custom API. This requires customization of the Target Deployment Port. Please refer to the Target Deployment Guide provided with the Opening the Target Deployment Port Editor.

In both of the above situations, Memory Profiling can use the heap management routines to detect memory leaks, array bounds and other memory-related defects.

Note Application pointers and block sizes can be modified by Memory Profiling in order to detect ABWL errors (Late Detect Array Bounds Write). Actual-pointer and actual-size refer to the memory data handled by Memory Profiling, whereas user pointer and user-size refer to the memory handled natively by the application-under-analysis. This distinction is important for the Memory Profiling ABWL and Red zone settings.

Target Deployment Port API

The Target Deployment Port library provides the following API for Memory Profiling:

void * _PurifyLTHeapAction ( _PurifyLT_API_ACTION, void *, RTRT_U_INT32, RTRT_U_INT8 );

In the function _PurifyLTHeapAction the first parameter is the type of action that will be or has been performed on the memory block pointed by the second parameter. The following actions can be used:

typedef enum {

_PurifyLT_API_ALLOC,

_PurifyLT_API_BEFORE_REALLOC,

_PurifyLT_API_FREE

} _PurifyLT_API_ACTION;

The third parameter is the size of the block. The fourth parameter is either of the following constants:

#define _PurifyLT_NO_DELAYED_FREE 0

#define _PurifyLT_DELAYED_FREE 1

If an allocation or free has a size of 0 this fourth parameter indicates a delayed free in order to detect FWML (Late Detect Free Memory Write) and FFM (Freeing Freed Memory) errors. See the section on Memory Profiling Configuration Settings for Detect FFM, Detect FMWL, Free Queue Length and Free Queue Size.

A freed delay can only be performed if the block can be freed with RTRT_DO_FREE (situation 1) or ANSI free (situation 2). For example, if a function requires more parameters than the pointer to de-allocate, then the FMWL and FFM error detection cannot be supported and FFM errors will be indicated by an FUM (Freeing Unallocated Memory) error instead.

The following function returns the size of an allocated block, or 0 if the block was not declared to Memory Profiling. This allows you to implement a library function similar to the msize from Microsoft Visual 6.0.

RTRT_SIZE_T _PurifyLTHeapPtrSize ( void * );

The following function returns the actual-size of a memory block, depending on the size requested. Call this function before the actual allocation to find out the quantity of memory that is available for the block and the contiguous red zones that are to be monitored by Memory Profiling.

RTRT_SIZE_T _PurifyLTHeapActualSize ( RTRT_SIZE_T );

Examples

In the following examples, my_malloc, my_realloc, my_free and my_msize demonstrate the four supported memory heap behaviors.

The following routine declares an allocation:

void *my_malloc ( int partId, size_t size )

{

void *ret;

size_t actual_size = _PurifyLTHeapActualSize(size);

/* Here is any user code making ret a pointer to a heap or

simulated heap memory block of actual_size bytes */

...

/* After comes Memory Profiling action */

return _PurifyLTHeapAction ( _PurifyLT_API_ALLOC, ret, size, 0 );

/* The user-pointer is returned */

}

In situation 2, where you have access to a custom memory heap API, replace the "..." with the actual malloc API function.

For a my_calloc(size_t nelem, size_t elsize) , pass on nelem*elsize as the third parameter of the _PurifyLTHeapAction function. In this case, you might need to replace this operation with a function that takes into account the alignments of elements.

To declare a reallocation, two operations are required:

void *my_realloc ( int partId, void * ptr, size_t size )

{

void *ret;

size_t actual_size = _PurifyLTHeapActualSize(size);

/* Before comes first Memory Profiling action */

ret = _PurifyLTHeapAction ( _PurifyLT_API_BEFORE_REALLOC, ptr, size, 0 );

/* ret now contains the actual-pointer */

/* Here is any user code making ret a reallocated pointer to a heap or

simulated heap memory block of actual_size bytes */

...

/* After comes second Memory Profiling action */

return _PurifyLTHeapAction ( _PurifyLT_API_ALLOC, ret, size, 0 );

/* The user-pointer is returned */

}

To free memory without using the delay:

void my_free ( int partId, void * ptr )

{

/* Memory Profiling action comes first */

void *ret = _PurifyLTHeapAction ( _PurifyLT_API_FREE, ptr, 0, 0 );

/* Any code insuring actual deallocation of ret */

}

To free memory using a delay:

void my_free ( int partId, void * ptr )

{

/* Memory Profiling action comes first */

void *ret = _PurifyLTHeapAction ( _PurifyLT_API_FREE, ptr, 0, 1 );

/* Nothing to do here */

}

To obtain the user size of a block:

size_t my_msize ( int partId, void * ptr )

{

return _PurifyLTHeapPtrSize ( ptr );

}

Use the following macros to save customization time when dealing with functions that have the same prototypes as the standard ANSI functions:

#define _PurifyLT_MALLOC_LIKE(func) \

void *RTRT_CONCAT_MACRO(usr_,func) ( RTRT_SIZE_T size ) \

{ \

void *ret; \

ret = func ( _PurifyLTHeapActualSize ( size ) ); \

return _PurifyLTHeapAction ( _PurifyLT_API_ALLOC, ret, size, 0 ); \

}

#define _PurifyLT_CALLOC_LIKE(func) \

void *RTRT_CONCAT_MACRO(usr_,func) ( RTRT_SIZE_T nelem, RTRT_SIZE_T elsize ) \

{ \

void *ret; \

ret = func ( _PurifyLTHeapActualSize ( nelem * elsize ) ); \

return _PurifyLTHeapAction ( _PurifyLT_API_ALLOC, ret, nelem * elsize, 0 ); \

}

#define _PurifyLT_REALLOC_LIKE(func,delayed_free) \

void *RTRT_CONCAT_MACRO(usr_,func) ( void *ptr, RTRT_SIZE_T size ) \

{ \

void *ret; \

ret = func ( _PurifyLTHeapAction ( _PurifyLT_API_BEFORE_REALLOC, \

ptr, size, delayed_free ), \

_PurifyLTHeapActualSize ( size ) ); \

return _PurifyLTHeapAction ( _PurifyLT_API_ALLOC, ret, size, 0 ); \

}

#define _PurifyLT_FREE_LIKE(func,delayed_free) \

void RTRT_CONCAT_MACRO(usr_,func) ( void *ptr ) \

{ \

if ( delayed_free ) \

{ \

_PurifyLTHeapAction ( _PurifyLT_API_FREE, ptr, 0, delayed_free ); \

} \

else \

{ \

func ( _PurifyLTHeapAction ( _PurifyLT_API_FREE, ptr, 0, delayed_free ) ); \

} \

}

Related Topics

About Memory Profiling | Error Messages | Opening the Target Deployment Port Editor