| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #include "sqliteInt.h" |
| |
|
| | |
| | |
| | |
| | |
| | #ifdef SQLITE_MEMDEBUG |
| |
|
| | |
| | |
| | |
| | #ifdef __GLIBC__ |
| | extern int backtrace(void**,int); |
| | extern void backtrace_symbols_fd(void*const*,int,int); |
| | #else |
| | # define backtrace(A,B) 1 |
| | # define backtrace_symbols_fd(A,B,C) |
| | #endif |
| | #include <stdio.h> |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | struct MemBlockHdr { |
| | i64 iSize; |
| | struct MemBlockHdr *pNext, *pPrev; |
| | char nBacktrace; |
| | char nBacktraceSlots; |
| | u8 nTitle; |
| | u8 eType; |
| | int iForeGuard; |
| | }; |
| |
|
| | |
| | |
| | |
| | #define FOREGUARD 0x80F5E153 |
| | #define REARGUARD 0xE4676B53 |
| |
|
| | |
| | |
| | |
| | #define NCSIZE 1000 |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static struct { |
| | |
| | |
| | |
| | |
| | sqlite3_mutex *mutex; |
| |
|
| | |
| | |
| | |
| | struct MemBlockHdr *pFirst; |
| | struct MemBlockHdr *pLast; |
| | |
| | |
| | |
| | |
| | int nBacktrace; |
| | void (*xBacktrace)(int, int, void **); |
| |
|
| | |
| | |
| | |
| | int nTitle; |
| | char zTitle[100]; |
| |
|
| | |
| | |
| | |
| | |
| | int disallow; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | int nAlloc[NCSIZE]; |
| | int nCurrent[NCSIZE]; |
| | int mxCurrent[NCSIZE]; |
| |
|
| | } mem; |
| |
|
| |
|
| | |
| | |
| | |
| | static void adjustStats(int iSize, int increment){ |
| | int i = ROUND8(iSize)/8; |
| | if( i>NCSIZE-1 ){ |
| | i = NCSIZE - 1; |
| | } |
| | if( increment>0 ){ |
| | mem.nAlloc[i]++; |
| | mem.nCurrent[i]++; |
| | if( mem.nCurrent[i]>mem.mxCurrent[i] ){ |
| | mem.mxCurrent[i] = mem.nCurrent[i]; |
| | } |
| | }else{ |
| | mem.nCurrent[i]--; |
| | assert( mem.nCurrent[i]>=0 ); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){ |
| | struct MemBlockHdr *p; |
| | int *pInt; |
| | u8 *pU8; |
| | int nReserve; |
| |
|
| | p = (struct MemBlockHdr*)pAllocation; |
| | p--; |
| | assert( p->iForeGuard==(int)FOREGUARD ); |
| | nReserve = ROUND8(p->iSize); |
| | pInt = (int*)pAllocation; |
| | pU8 = (u8*)pAllocation; |
| | assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD ); |
| | |
| | |
| | |
| | |
| | while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 ); |
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | static int sqlite3MemSize(void *p){ |
| | struct MemBlockHdr *pHdr; |
| | if( !p ){ |
| | return 0; |
| | } |
| | pHdr = sqlite3MemsysGetHeader(p); |
| | return (int)pHdr->iSize; |
| | } |
| |
|
| | |
| | |
| | |
| | static int sqlite3MemInit(void *NotUsed){ |
| | UNUSED_PARAMETER(NotUsed); |
| | assert( (sizeof(struct MemBlockHdr)&7) == 0 ); |
| | if( !sqlite3GlobalConfig.bMemstat ){ |
| | |
| | |
| | mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); |
| | } |
| | return SQLITE_OK; |
| | } |
| |
|
| | |
| | |
| | |
| | static void sqlite3MemShutdown(void *NotUsed){ |
| | UNUSED_PARAMETER(NotUsed); |
| | mem.mutex = 0; |
| | } |
| |
|
| | |
| | |
| | |
| | static int sqlite3MemRoundup(int n){ |
| | return ROUND8(n); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | static void randomFill(char *pBuf, int nByte){ |
| | unsigned int x, y, r; |
| | x = SQLITE_PTR_TO_INT(pBuf); |
| | y = nByte | 1; |
| | while( nByte >= 4 ){ |
| | x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); |
| | y = y*1103515245 + 12345; |
| | r = x ^ y; |
| | *(int*)pBuf = r; |
| | pBuf += 4; |
| | nByte -= 4; |
| | } |
| | while( nByte-- > 0 ){ |
| | x = (x>>1) ^ (-(int)(x&1) & 0xd0000001); |
| | y = y*1103515245 + 12345; |
| | r = x ^ y; |
| | *(pBuf++) = r & 0xff; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | static void *sqlite3MemMalloc(int nByte){ |
| | struct MemBlockHdr *pHdr; |
| | void **pBt; |
| | char *z; |
| | int *pInt; |
| | void *p = 0; |
| | int totalSize; |
| | int nReserve; |
| | sqlite3_mutex_enter(mem.mutex); |
| | assert( mem.disallow==0 ); |
| | nReserve = ROUND8(nByte); |
| | totalSize = nReserve + sizeof(*pHdr) + sizeof(int) + |
| | mem.nBacktrace*sizeof(void*) + mem.nTitle; |
| | p = malloc(totalSize); |
| | if( p ){ |
| | z = p; |
| | pBt = (void**)&z[mem.nTitle]; |
| | pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; |
| | pHdr->pNext = 0; |
| | pHdr->pPrev = mem.pLast; |
| | if( mem.pLast ){ |
| | mem.pLast->pNext = pHdr; |
| | }else{ |
| | mem.pFirst = pHdr; |
| | } |
| | mem.pLast = pHdr; |
| | pHdr->iForeGuard = FOREGUARD; |
| | pHdr->eType = MEMTYPE_HEAP; |
| | pHdr->nBacktraceSlots = mem.nBacktrace; |
| | pHdr->nTitle = mem.nTitle; |
| | if( mem.nBacktrace ){ |
| | void *aAddr[40]; |
| | pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; |
| | memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); |
| | assert(pBt[0]); |
| | if( mem.xBacktrace ){ |
| | mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); |
| | } |
| | }else{ |
| | pHdr->nBacktrace = 0; |
| | } |
| | if( mem.nTitle ){ |
| | memcpy(z, mem.zTitle, mem.nTitle); |
| | } |
| | pHdr->iSize = nByte; |
| | adjustStats(nByte, +1); |
| | pInt = (int*)&pHdr[1]; |
| | pInt[nReserve/sizeof(int)] = REARGUARD; |
| | randomFill((char*)pInt, nByte); |
| | memset(((char*)pInt)+nByte, 0x65, nReserve-nByte); |
| | p = (void*)pInt; |
| | } |
| | sqlite3_mutex_leave(mem.mutex); |
| | return p; |
| | } |
| |
|
| | |
| | |
| | |
| | static void sqlite3MemFree(void *pPrior){ |
| | struct MemBlockHdr *pHdr; |
| | void **pBt; |
| | char *z; |
| | assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0 |
| | || mem.mutex!=0 ); |
| | pHdr = sqlite3MemsysGetHeader(pPrior); |
| | pBt = (void**)pHdr; |
| | pBt -= pHdr->nBacktraceSlots; |
| | sqlite3_mutex_enter(mem.mutex); |
| | if( pHdr->pPrev ){ |
| | assert( pHdr->pPrev->pNext==pHdr ); |
| | pHdr->pPrev->pNext = pHdr->pNext; |
| | }else{ |
| | assert( mem.pFirst==pHdr ); |
| | mem.pFirst = pHdr->pNext; |
| | } |
| | if( pHdr->pNext ){ |
| | assert( pHdr->pNext->pPrev==pHdr ); |
| | pHdr->pNext->pPrev = pHdr->pPrev; |
| | }else{ |
| | assert( mem.pLast==pHdr ); |
| | mem.pLast = pHdr->pPrev; |
| | } |
| | z = (char*)pBt; |
| | z -= pHdr->nTitle; |
| | adjustStats((int)pHdr->iSize, -1); |
| | randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + |
| | (int)pHdr->iSize + sizeof(int) + pHdr->nTitle); |
| | free(z); |
| | sqlite3_mutex_leave(mem.mutex); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void *sqlite3MemRealloc(void *pPrior, int nByte){ |
| | struct MemBlockHdr *pOldHdr; |
| | void *pNew; |
| | assert( mem.disallow==0 ); |
| | assert( (nByte & 7)==0 ); |
| | pOldHdr = sqlite3MemsysGetHeader(pPrior); |
| | pNew = sqlite3MemMalloc(nByte); |
| | if( pNew ){ |
| | memcpy(pNew, pPrior, (int)(nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize)); |
| | if( nByte>pOldHdr->iSize ){ |
| | randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - (int)pOldHdr->iSize); |
| | } |
| | sqlite3MemFree(pPrior); |
| | } |
| | return pNew; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3MemSetDefault(void){ |
| | static const sqlite3_mem_methods defaultMethods = { |
| | sqlite3MemMalloc, |
| | sqlite3MemFree, |
| | sqlite3MemRealloc, |
| | sqlite3MemSize, |
| | sqlite3MemRoundup, |
| | sqlite3MemInit, |
| | sqlite3MemShutdown, |
| | 0 |
| | }; |
| | sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3MemdebugSetType(void *p, u8 eType){ |
| | if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ |
| | struct MemBlockHdr *pHdr; |
| | pHdr = sqlite3MemsysGetHeader(p); |
| | assert( pHdr->iForeGuard==FOREGUARD ); |
| | pHdr->eType = eType; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3MemdebugHasType(const void *p, u8 eType){ |
| | int rc = 1; |
| | if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ |
| | struct MemBlockHdr *pHdr; |
| | pHdr = sqlite3MemsysGetHeader(p); |
| | assert( pHdr->iForeGuard==FOREGUARD ); |
| | if( (pHdr->eType&eType)==0 ){ |
| | rc = 0; |
| | } |
| | } |
| | return rc; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | int sqlite3MemdebugNoType(const void *p, u8 eType){ |
| | int rc = 1; |
| | if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ |
| | struct MemBlockHdr *pHdr; |
| | pHdr = sqlite3MemsysGetHeader(p); |
| | assert( pHdr->iForeGuard==FOREGUARD ); |
| | if( (pHdr->eType&eType)!=0 ){ |
| | rc = 0; |
| | } |
| | } |
| | return rc; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void sqlite3MemdebugBacktrace(int depth){ |
| | if( depth<0 ){ depth = 0; } |
| | if( depth>20 ){ depth = 20; } |
| | depth = (depth+1)&0xfe; |
| | mem.nBacktrace = depth; |
| | } |
| |
|
| | void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ |
| | mem.xBacktrace = xBacktrace; |
| | } |
| |
|
| | |
| | |
| | |
| | void sqlite3MemdebugSettitle(const char *zTitle){ |
| | unsigned int n = sqlite3Strlen30(zTitle) + 1; |
| | sqlite3_mutex_enter(mem.mutex); |
| | if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; |
| | memcpy(mem.zTitle, zTitle, n); |
| | mem.zTitle[n] = 0; |
| | mem.nTitle = ROUND8(n); |
| | sqlite3_mutex_leave(mem.mutex); |
| | } |
| |
|
| | void sqlite3MemdebugSync(){ |
| | struct MemBlockHdr *pHdr; |
| | for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ |
| | void **pBt = (void**)pHdr; |
| | pBt -= pHdr->nBacktraceSlots; |
| | mem.xBacktrace((int)pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | void sqlite3MemdebugDump(const char *zFilename){ |
| | FILE *out; |
| | struct MemBlockHdr *pHdr; |
| | void **pBt; |
| | int i; |
| | out = fopen(zFilename, "w"); |
| | if( out==0 ){ |
| | fprintf(stderr, "** Unable to output memory debug output log: %s **\n", |
| | zFilename); |
| | return; |
| | } |
| | for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ |
| | char *z = (char*)pHdr; |
| | z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; |
| | fprintf(out, "**** %lld bytes at %p from %s ****\n", |
| | pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); |
| | if( pHdr->nBacktrace ){ |
| | fflush(out); |
| | pBt = (void**)pHdr; |
| | pBt -= pHdr->nBacktraceSlots; |
| | backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); |
| | fprintf(out, "\n"); |
| | } |
| | } |
| | fprintf(out, "COUNTS:\n"); |
| | for(i=0; i<NCSIZE-1; i++){ |
| | if( mem.nAlloc[i] ){ |
| | fprintf(out, " %5d: %10d %10d %10d\n", |
| | i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]); |
| | } |
| | } |
| | if( mem.nAlloc[NCSIZE-1] ){ |
| | fprintf(out, " %5d: %10d %10d %10d\n", |
| | NCSIZE*8-8, mem.nAlloc[NCSIZE-1], |
| | mem.nCurrent[NCSIZE-1], mem.mxCurrent[NCSIZE-1]); |
| | } |
| | fclose(out); |
| | } |
| |
|
| | |
| | |
| | |
| | int sqlite3MemdebugMallocCount(){ |
| | int i; |
| | int nTotal = 0; |
| | for(i=0; i<NCSIZE; i++){ |
| | nTotal += mem.nAlloc[i]; |
| | } |
| | return nTotal; |
| | } |
| |
|
| |
|
| | #endif |
| |
|