Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to find a memory leak in C++
    text
    copied!<p>What would be a good way to detect a C++ memory leak in an embedded environment? I tried overloading the new operator to log every data allocation, but I must have done something wrong, that approach isn't working. Has anyone else run into a similar situation?</p> <p>This is the code for the new and delete operator overloading.</p> <p>EDIT:</p> <p>Full disclosure: I am looking for a memory leak in my program and I am using this code that someone else wrote to overload the new and delete operator. Part of my problem is the fact that I don't fully understand what it does. I know that the goal is to log the address of the caller and previous caller, the size of the allocation, a 1 if we are allocating, a 2 if we are deallocation. plus the name of the thread that is running. </p> <p>Thanks for all the suggestions, I am going to try a different approach that someone here at work suggested. If it works, I will post it here. </p> <p>Thanks again to all you first-rate programmers for taking the time to answer.</p> <p>StackOverflow rocks!</p> <p><strong>Conclusion</strong></p> <p>Thanks for all the answers. Unfortunately, I had to move on to a different more pressing issue. This leak only occurred under a highly unlikely scenario. I feel crappy about just dropping it, I may go back to it if I have more time. I chose the answer I am most likely to use.</p> <pre><code>#include &lt;stdlib.h&gt; #include "stdio.h" #include "nucleus.h" #include "plus/inc/dm_defs.h" #include "plus/inc/pm_defs.h" #include "posix\inc\posix.h" extern void* TCD_Current_Thread; extern "C" void rd_write_text(char * text); extern PM_PCB * PMD_Created_Pools_List; typedef struct { void* addr; uint16_t size; uint16_t flags; } MemLogEntryNarrow_t; typedef struct { void* addr; uint16_t size; uint16_t flags; void* caller; void* prev_caller; void* taskid; uint32_t timestamp; } MemLogEntryWide_t; //size lookup table unsigned char MEM_bitLookupTable[] = { 0,1,1,2,1,2,2,3,1,2,2,3,1,3,3,4 }; //#pragma CODE_SECTION ("section_ramset1_0") void *::operator new(unsigned int size) { asm(" STR R14, [R13, #0xC]"); //save stack address temp[0] asm(" STR R13, [R13, #0x10]"); //save pc return address temp[1] if ( loggingEnabled ) { uint32_t savedInterruptState; uint32_t currentIndex; // protect the thread unsafe section. savedInterruptState = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS); // Note that this code is FRAGILE. It peeks backwards on the stack to find the return // address of the caller. The location of the return address on the stack can be easily changed // as a result of other changes in this function (i.e. adding local variables, etc). // The offsets may need to be adjusted if this function is touched. volatile unsigned int temp[2]; unsigned int *addr = (unsigned int *)temp[0] - 1; unsigned int count = 1 + (0x20/4); //current stack space *** //Scan for previous store while ((*addr &amp; 0xFFFF0000) != 0xE92D0000) { if ((*addr &amp; 0xFFFFF000) == 0xE24DD000) { //add offset in words count += ((*addr &amp; 0xFFF) &gt;&gt; 2); } addr--; } count += MEM_bitLookupTable[*addr &amp; 0xF]; count += MEM_bitLookupTable[(*addr &gt;&gt;4) &amp; 0xF]; count += MEM_bitLookupTable[(*addr &gt;&gt; 8) &amp; 0xF]; count += MEM_bitLookupTable[(*addr &gt;&gt; 12) &amp; 0xF]; addr = (unsigned int *)temp[1] + count; // FRAGILE CODE ENDS HERE currentIndex = currentMemLogWriteIndex; currentMemLogWriteIndex++; if ( memLogNarrow ) { if (currentMemLogWriteIndex &gt;= MEMLOG_SIZE/2 ) { loggingEnabled = false; rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n"); } // advance the read index if necessary. if ( currentMemLogReadIndex == currentMemLogWriteIndex ) { currentMemLogReadIndex++; if ( currentMemLogReadIndex == MEMLOG_SIZE/2 ) { currentMemLogReadIndex = 0; } } NU_Local_Control_Interrupts(savedInterruptState); //Standard operator //(For Partition Analysis we have to consider that if we alloc size of 0 always as size of 1 then are partitions must be optimized for this) if (size == 0) size = 1; ((MemLogEntryNarrow_t*)memLog)[currentIndex].size = size; ((MemLogEntryNarrow_t*)memLog)[currentIndex].flags = 1; //allocated //Standard operator void * ptr; ptr = malloc(size); ((MemLogEntryNarrow_t*)memLog)[currentIndex].addr = ptr; return ptr; } else { if (currentMemLogWriteIndex &gt;= MEMLOG_SIZE/6 ) { loggingEnabled = false; rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n"); } // advance the read index if necessary. if ( currentMemLogReadIndex == currentMemLogWriteIndex ) { currentMemLogReadIndex++; if ( currentMemLogReadIndex == MEMLOG_SIZE/6 ) { currentMemLogReadIndex = 0; } } ((MemLogEntryWide_t*)memLog)[currentIndex].caller = (void *)(temp[0] - 4); ((MemLogEntryWide_t*)memLog)[currentIndex].prev_caller = (void *)*addr; NU_Local_Control_Interrupts(savedInterruptState); ((MemLogEntryWide_t*)memLog)[currentIndex].taskid = (void *)TCD_Current_Thread; ((MemLogEntryWide_t*)memLog)[currentIndex].size = size; ((MemLogEntryWide_t*)memLog)[currentIndex].flags = 1; //allocated ((MemLogEntryWide_t*)memLog)[currentIndex].timestamp = *(volatile uint32_t *)0xfffbc410; // for arm9 //Standard operator if (size == 0) size = 1; void * ptr; ptr = malloc(size); ((MemLogEntryWide_t*)memLog)[currentIndex].addr = ptr; return ptr; } } else { //Standard operator if (size == 0) size = 1; void * ptr; ptr = malloc(size); return ptr; } } //#pragma CODE_SECTION ("section_ramset1_0") void ::operator delete(void *ptr) { uint32_t savedInterruptState; uint32_t currentIndex; asm(" STR R14, [R13, #0xC]"); //save stack address temp[0] asm(" STR R13, [R13, #0x10]"); //save pc return address temp[1] if ( loggingEnabled ) { savedInterruptState = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS); // Note that this code is FRAGILE. It peeks backwards on the stack to find the return // address of the caller. The location of the return address on the stack can be easily changed // as a result of other changes in this function (i.e. adding local variables, etc). // The offsets may need to be adjusted if this function is touched. volatile unsigned int temp[2]; unsigned int *addr = (unsigned int *)temp[0] - 1; unsigned int count = 1 + (0x20/4); //current stack space *** //Scan for previous store while ((*addr &amp; 0xFFFF0000) != 0xE92D0000) { if ((*addr &amp; 0xFFFFF000) == 0xE24DD000) { //add offset in words count += ((*addr &amp; 0xFFF) &gt;&gt; 2); } addr--; } count += MEM_bitLookupTable[*addr &amp; 0xF]; count += MEM_bitLookupTable[(*addr &gt;&gt;4) &amp; 0xF]; count += MEM_bitLookupTable[(*addr &gt;&gt; 8) &amp; 0xF]; count += MEM_bitLookupTable[(*addr &gt;&gt; 12) &amp; 0xF]; addr = (unsigned int *)temp[1] + count; // FRAGILE CODE ENDS HERE currentIndex = currentMemLogWriteIndex; currentMemLogWriteIndex++; if ( memLogNarrow ) { if ( currentMemLogWriteIndex &gt;= MEMLOG_SIZE/2 ) { loggingEnabled = false; rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n"); } // advance the read index if necessary. if ( currentMemLogReadIndex == currentMemLogWriteIndex ) { currentMemLogReadIndex++; if ( currentMemLogReadIndex == MEMLOG_SIZE/2 ) { currentMemLogReadIndex = 0; } } NU_Local_Control_Interrupts(savedInterruptState); // finish logging the fields. these are thread safe so they dont need to be inside the protected section. ((MemLogEntryNarrow_t*)memLog)[currentIndex].addr = ptr; ((MemLogEntryNarrow_t*)memLog)[currentIndex].size = 0; ((MemLogEntryNarrow_t*)memLog)[currentIndex].flags = 2; //unallocated } else { ((MemLogEntryWide_t*)memLog)[currentIndex].caller = (void *)(temp[0] - 4); ((MemLogEntryWide_t*)memLog)[currentIndex].prev_caller = (void *)*addr; if ( currentMemLogWriteIndex &gt;= MEMLOG_SIZE/6 ) { loggingEnabled = false; rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n"); } // advance the read index if necessary. if ( currentMemLogReadIndex == currentMemLogWriteIndex ) { currentMemLogReadIndex++; if ( currentMemLogReadIndex == MEMLOG_SIZE/6 ) { currentMemLogReadIndex = 0; } } NU_Local_Control_Interrupts(savedInterruptState); // finish logging the fields. these are thread safe so they dont need to be inside the protected section. ((MemLogEntryWide_t*)memLog)[currentIndex].addr = ptr; ((MemLogEntryWide_t*)memLog)[currentIndex].size = 0; ((MemLogEntryWide_t*)memLog)[currentIndex].flags = 2; //unallocated ((MemLogEntryWide_t*)memLog)[currentIndex].taskid = (void *)TCD_Current_Thread; ((MemLogEntryWide_t*)memLog)[currentIndex].timestamp = *(volatile uint32_t *)0xfffbc410; // for arm9 } //Standard operator if (ptr != NULL) { free(ptr); } } else { //Standard operator if (ptr != NULL) { free(ptr); } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload