Index: ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/ChangeLog,v retrieving revision 1.39 diff -u -8 -p -r1.39 ChangeLog --- ChangeLog 17 May 2006 16:14:02 -0000 1.39 +++ ChangeLog 5 Aug 2008 12:58:25 -0000 @@ -1,8 +1,14 @@ +2008-08-05 Stefan Sommerfeld + + * cdl/memalloc.cdl: Added MungWall Memory Leak/Error detector + * include/dlmalloc.hxx: Added MungWall support + * tests/mungwall.cxx: MungWall test + 2006-05-17 Andrew Lunn * doc/memalloc.sgml: Fix parameters for calloc. Reported by Andy Jackson. 2005-09-30 Alexander Neundorf * doc/memalloc.sgml: two minor fixes Index: cdl/memalloc.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/cdl/memalloc.cdl,v retrieving revision 1.15 diff -u -8 -p -r1.15 memalloc.cdl --- cdl/memalloc.cdl 30 Jul 2005 11:42:55 -0000 1.15 +++ cdl/memalloc.cdl 5 Aug 2008 12:58:26 -0000 @@ -192,16 +192,38 @@ cdl_package CYGPKG_MEMALLOC { legal_values 3 to 10 default_value 3 description " This option controls the minimum alignment that the allocated memory blocks are aligned on, specified as 2^N. Note that using large mininum alignments can lead to excessive memory wastage." } + + cdl_option CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL { + display "MungWall Memory Leak/Error detector" + requires CYGPKG_ISOINFRA + default_value 0 + description " + MungWall can be used to detect memory corruptions and find + memory leaks. As a side effect every memory allocation needs + a bit more memory and allocations are a bit slower." + } + + cdl_option CYGNUM_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL_SAFEAREA { + display "MungWall safe area" + flavor data + legal_values 16 to 65536 + default_value 32 + description " + MungWall allocates space before and after a memory block to + find memory corruptions. This value specifies how much space + should be reserved. Please have the alignment in mind and use + values multiple of 16." + } } cdl_component CYGPKG_MEMALLOC_ALLOCATOR_SEPMETA { display "Variable block allocator with separate metadata" flavor none no_define description " This component contains configuration options related to the @@ -399,17 +421,17 @@ cdl_package CYGPKG_MEMALLOC { building this package. These flags are removed from the set of global flags if present." } cdl_option CYGPKG_MEMALLOC_TESTS { display "Tests" flavor data no_define - calculated { "tests/dlmalloc1 tests/dlmalloc2 tests/heaptest tests/kmemfix1 tests/kmemvar1 tests/malloc1 tests/malloc2 tests/malloc3 tests/malloc4 tests/memfix1 tests/memfix2 tests/memvar1 tests/memvar2 tests/realloc tests/sepmeta1 tests/sepmeta2" } + calculated { "tests/dlmalloc1 tests/dlmalloc2 tests/heaptest tests/kmemfix1 tests/kmemvar1 tests/malloc1 tests/malloc2 tests/malloc3 tests/malloc4 tests/memfix1 tests/memfix2 tests/memvar1 tests/memvar2 tests/realloc tests/sepmeta1 tests/sepmeta2 tests/mungwall" } description " This option specifies the set of tests for this package." } } } # ==================================================================== # EOF memalloc.cdl Index: include/dlmalloc.hxx =================================================================== RCS file: /cvs/ecos/ecos/packages/services/memalloc/common/current/include/dlmalloc.hxx,v retrieving revision 1.3 diff -u -8 -p -r1.3 dlmalloc.hxx --- include/dlmalloc.hxx 23 May 2002 23:08:43 -0000 1.3 +++ include/dlmalloc.hxx 5 Aug 2008 12:58:33 -0000 @@ -87,86 +87,291 @@ #ifdef CYGFUN_KERNEL_THREADS_TIMER # include // cyg_tick_count #endif // TYPE DEFINITIONS + +#ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL + +extern "C" +{ + extern unsigned char _stext[]; + extern unsigned char __ram_data_start[]; +}; + +struct MungMemInfo +{ + cyg_uint32 header; + struct MungMemInfo *pred; + struct MungMemInfo *succ; + cyg_int32 size; + cyg_int32 userdata; + cyg_uint32 return_addr[7]; +}; + +#define MUNGWALL_TOPOFFSET CYGNUM_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL_SAFEAREA +#define MUNGWALL_BOTTOMOFFSET CYGNUM_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL_SAFEAREA +#define MUNGWALL_OFFSET (MUNGWALL_TOPOFFSET + MUNGWALL_BOTTOMOFFSET + sizeof(struct MungMemInfo)) + +#include +#include + +#ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_THREADAWARE +#define MUNGWALL_LOCK cyg_scheduler_lock() +#define MUNGWALL_UNLOCK cyg_scheduler_unlock() +#else +#define MUNGWALL_LOCK +#define MUNGWALL_UNLOCK +#endif + +#endif + class Cyg_Mempool_dlmalloc { protected: #ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_THREADAWARE Cyg_Mempolt2 mypool; #else Cyg_Mempool_dlmalloc_Implementation mypool; #endif public: // Constructor: gives the base and size of the arena in which memory is // to be carved out, note that management structures are taken from the // same arena. Cyg_Mempool_dlmalloc( cyg_uint8 *base, cyg_int32 size, CYG_ADDRWORD argthru=0 ) - : mypool( base, size, argthru ) {} + : mypool( base, size, argthru ) { +#ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL + m_first_entry = 0; + m_last_entry = 0; +#endif + } // Destructor ~Cyg_Mempool_dlmalloc() {} // get some memory; wait if none available // if we aren't configured to be thread-aware this is irrelevant #ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_THREADAWARE cyg_uint8 * - alloc( cyg_int32 size ) { return mypool.alloc( size ); } + alloc( cyg_int32 size ) { +#ifndef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL + return mypool.alloc( size ); +#else + return(memInit(mypool.alloc( size + MUNGWALL_OFFSET),size)); +#endif + } # ifdef CYGFUN_KERNEL_THREADS_TIMER // get some memory with a timeout cyg_uint8 * alloc( cyg_int32 size, cyg_tick_count delay_timeout ) { +#ifndef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL return mypool.alloc( size, delay_timeout ); +#else + return(memInit(mypool.alloc( size + MUNGWALL_OFFSET, delay_timeout ),size)); +#endif } # endif #endif // get some memory, return NULL if none available cyg_uint8 * - try_alloc( cyg_int32 size ) { return mypool.try_alloc( size ); } + try_alloc( cyg_int32 size ) { +#ifndef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL + return mypool.try_alloc( size ); +#else + return(memInit(mypool.try_alloc( size + MUNGWALL_OFFSET),size)); +#endif + } // resize existing allocation, if oldsize is non-NULL, previous // allocation size is placed into it. If previous size not available, // it is set to 0. NB previous allocation size may have been rounded up. // Occasionally the allocation can be adjusted *backwards* as well as, // or instead of forwards, therefore the address of the resized // allocation is returned, or NULL if no resizing was possible. // Note that this differs from ::realloc() in that no attempt is // made to call malloc() if resizing is not possible - that is left // to higher layers. The data is copied from old to new though. // The effects of alloc_ptr==NULL or newsize==0 are undefined cyg_uint8 * resize_alloc( cyg_uint8 *alloc_ptr, cyg_int32 newsize, cyg_int32 *oldsize ) { +#ifndef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL return mypool.resize_alloc( alloc_ptr, newsize, oldsize); +#else + return(memInit(mypool.resize_alloc( &alloc_ptr[-(MUNGWALL_OFFSET - MUNGWALL_BOTTOMOFFSET)], newsize + MUNGWALL_OFFSET, oldsize + MUNGWALL_OFFSET),newsize)); +#endif } // free the memory back to the pool // returns true on success cyg_bool - free( cyg_uint8 *ptr, cyg_int32 size=0 ) { return mypool.free(ptr, size); } + free( cyg_uint8 *ptr, cyg_int32 size=0 ) { +#ifndef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL + return mypool.free(ptr, size); +#else + return(freeMem(ptr,size)); +#endif + } // Get memory pool status // flags is a bitmask of requested fields to fill in. The flags are // defined in common.hxx void get_status( cyg_mempool_status_flag_t flags, Cyg_Mempool_Status &status ) { // set to 0 - if there's anything really waiting, it will be set to // 1 later status.waiting = 0; mypool.get_status( flags, status ); } + +#ifdef CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL + void snapShotMemory() + { + MUNGWALL_LOCK; + struct MungMemInfo *memi = m_first_entry; + while(memi != 0) + { + memi->userdata++; + memi = memi->succ; + } + MUNGWALL_UNLOCK; + } + + void dumpMemory(cyg_int32 trigger) + { + MUNGWALL_LOCK; + struct MungMemInfo *memi = m_first_entry; + while(memi != 0) + { + if (memi->userdata < trigger) + { + diag_printf("MEM ENTRY: %p:%d\n",&((cyg_uint8 *) memi)[MUNGWALL_OFFSET - MUNGWALL_BOTTOMOFFSET],memi->size); + diag_printf("PC:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",memi->return_addr[0],memi->return_addr[1],memi->return_addr[2], + memi->return_addr[3],memi->return_addr[4],memi->return_addr[5],memi->return_addr[6]); + } + memi = memi->succ; + } + MUNGWALL_UNLOCK; + } + +private: + cyg_uint8 *memInit(cyg_uint8 *mem, cyg_int32 size) + { + if (mem) + { + memset(mem,0,sizeof(struct MungMemInfo)); + memset(&mem[sizeof(struct MungMemInfo)],0xcd,MUNGWALL_BOTTOMOFFSET + MUNGWALL_TOPOFFSET + size); + struct MungMemInfo *memi = (struct MungMemInfo *) mem; + memi->header = 0x00badcafe; + memi->size = size; + MUNGWALL_LOCK; + memi->pred = m_last_entry; + if (m_last_entry) + { + m_last_entry->succ = memi; + } + if (m_first_entry == 0) + { + m_first_entry = memi; + } + cyg_uint32 *stack = reinterpret_cast(&memi); + cyg_int32 retnum = 0; + for (cyg_int32 i=0;i<200;i++) + { + if ((stack[i] >= ((cyg_uint32) _stext)) && (stack[i] < ((cyg_uint32) __ram_data_start))) + { + memi->return_addr[retnum] = stack[i]; + if (++retnum == 7) + { + break; + } + } + } + m_last_entry = memi; + MUNGWALL_UNLOCK; + return(&mem[MUNGWALL_TOPOFFSET + sizeof(struct MungMemInfo)]); + } + return(mem); + } + + cyg_bool freeMem(cyg_uint8 *mem, cyg_int32 size) + { + if (mem == 0) + { + return mypool.free(mem, size); + } + struct MungMemInfo *memi = (struct MungMemInfo *) &mem[-(MUNGWALL_OFFSET - MUNGWALL_BOTTOMOFFSET)]; + if (memi->header == 0x0badcafe) + { + MUNGWALL_LOCK; + if (m_first_entry == memi) + { + m_first_entry = memi->succ; + } + if (m_last_entry == memi) + { + m_last_entry = memi->pred; + } + if (memi->pred) + { + memi->pred->succ = memi->succ; + } + if (memi->succ) + { + memi->succ->pred = memi->pred; + } + MUNGWALL_UNLOCK; + + cyg_uint8 *chkmem = &mem[-(MUNGWALL_TOPOFFSET)]; + for (cyg_int32 i=0;ireturn_addr[0]); + for (cyg_int32 j=(i & (~7));jsize]; + for (cyg_int32 i=MUNGWALL_BOTTOMOFFSET-1;i>=0;i--) + { + if (chkmem[i] != 0xcd) + { + diag_printf("CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_MUNGWALL HIT: %d byte overwritten after: %p at 0x%08x\n",i + 1,mem,memi->return_addr[0]); + for (cyg_int32 j=0;jheader); + } + return mypool.free(&mem[-(MUNGWALL_OFFSET - MUNGWALL_BOTTOMOFFSET)], size + MUNGWALL_OFFSET); + } + + struct MungMemInfo *m_first_entry; + struct MungMemInfo *m_last_entry; +#endif }; #endif // ifndef __MALLOC_IMPL_WANTED #endif // ifndef CYGONCE_MEMALLOC_DLMALLOC_HXX // EOF dlmalloc.hxx