/*** 2007 August 15**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.******************************************************************************* This file contains low-level memory allocation drivers for when** SQLite will use the standard C-library malloc/realloc/free interface** to obtain the memory it needs while adding lots of additional debugging** information to each allocation in order to help detect and fix memory** leaks and memory usage errors.**** This file contains implementations of the low-level memory allocation** routines specified in the sqlite3_mem_methods object.*/#include "sqliteInt.h"/*** This version of the memory allocator is used only if the** SQLITE_MEMDEBUG macro is defined*/#ifdef SQLITE_MEMDEBUG/*** The backtrace functionality is only available with GLIBC*/#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>/*** Each memory allocation looks like this:**** ------------------------------------------------------------------------** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard |** ------------------------------------------------------------------------**** The application code sees only a pointer to the allocation. We have** to back up from the allocation pointer to find the MemBlockHdr. The** MemBlockHdr tells us the size of the allocation and the number of** backtrace pointers. There is also a guard word at the end of the** MemBlockHdr.*/struct MemBlockHdr {i64 iSize; /* Size of this allocation */struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */char nBacktrace; /* Number of backtraces on this alloc */char nBacktraceSlots; /* Available backtrace slots */u8 nTitle; /* Bytes of title; includes '0円' */u8 eType; /* Allocation type code */int iForeGuard; /* Guard word for sanity */};/*** Guard words*/#define FOREGUARD 0x80F5E153#define REARGUARD 0xE4676B53/*** Number of malloc size increments to track.*/#define NCSIZE 1000/*** All of the static variables used by this module are collected** into a single structure named "mem". This is to keep the** static variables organized and to reduce namespace pollution** when this module is combined with other in the amalgamation.*/static struct {/*** Mutex to control access to the memory allocation subsystem.*/sqlite3_mutex *mutex;/*** Head and tail of a linked list of all outstanding allocations*/struct MemBlockHdr *pFirst;struct MemBlockHdr *pLast;/*** The number of levels of backtrace to save in new allocations.*/int nBacktrace;void (*xBacktrace)(int, int, void **);/*** Title text to insert in front of each block*/int nTitle; /* Bytes of zTitle to save. Includes '0円' and padding */char zTitle[100]; /* The title text *//*** sqlite3MallocDisallow() increments the following counter.** sqlite3MallocAllow() decrements it.*/int disallow; /* Do not allow memory allocation *//*** Gather statistics on the sizes of memory allocations.** nAlloc[i] is the number of allocation attempts of i*8** bytes. i==NCSIZE is the number of allocation attempts for** sizes more than NCSIZE*8 bytes.*/int nAlloc[NCSIZE]; /* Total number of allocations */int nCurrent[NCSIZE]; /* Current number of allocations */int mxCurrent[NCSIZE]; /* Highwater mark for nCurrent */} mem;/*** Adjust memory usage statistics*/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 );}}/*** Given an allocation, find the MemBlockHdr for that allocation.**** This routine checks the guards at either end of the allocation and** if they are incorrect it asserts.*/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 );/* This checks any of the "extra" bytes allocated due** to rounding up to an 8 byte boundary to ensure** they haven't been overwritten.*/while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );return p;}/*** Return the number of bytes currently allocated at address p.*/static int sqlite3MemSize(void *p){struct MemBlockHdr *pHdr;if( !p ){return 0;}pHdr = sqlite3MemsysGetHeader(p);return (int)pHdr->iSize;}/*** Initialize the memory allocation subsystem.*/static int sqlite3MemInit(void *NotUsed){UNUSED_PARAMETER(NotUsed);assert( (sizeof(struct MemBlockHdr)&7) == 0 );if( !sqlite3GlobalConfig.bMemstat ){/* If memory status is enabled, then the malloc.c wrapper will already** hold the STATIC_MEM mutex when the routines here are invoked. */mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);}return SQLITE_OK;}/*** Deinitialize the memory allocation subsystem.*/static void sqlite3MemShutdown(void *NotUsed){UNUSED_PARAMETER(NotUsed);mem.mutex = 0;}/*** Round up a request size to the next valid allocation size.*/static int sqlite3MemRoundup(int n){return ROUND8(n);}/*** Fill a buffer with pseudo-random bytes. This is used to preset** the content of a new memory allocation to unpredictable values and** to clear the content of a freed allocation to unpredictable values.*/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;}}/*** Allocate nByte bytes of memory.*/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;}/*** Free memory.*/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);}/*** Change the size of an existing memory allocation.**** For this debugging implementation, we *always* make a copy of the** allocation into a new place in memory. In this way, if the** higher level code is using pointer to the old allocation, it is** much more likely to break and we are much more liking to find** the error.*/static void *sqlite3MemRealloc(void *pPrior, int nByte){struct MemBlockHdr *pOldHdr;void *pNew;assert( mem.disallow==0 );assert( (nByte & 7)==0 ); /* EV: R-46199-30249 */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;}/*** Populate the low-level memory allocation function pointers in** sqlite3GlobalConfig.m with pointers to the routines in this file.*/void sqlite3MemSetDefault(void){static const sqlite3_mem_methods defaultMethods = {sqlite3MemMalloc,sqlite3MemFree,sqlite3MemRealloc,sqlite3MemSize,sqlite3MemRoundup,sqlite3MemInit,sqlite3MemShutdown,0};sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);}/*** Set the "type" of an allocation.*/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;}}/*** Return TRUE if the mask of type in eType matches the type of the** allocation p. Also return true if p==NULL.**** This routine is designed for use within an assert() statement, to** verify the type of an allocation. For example:**** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );*/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 ); /* Allocation is valid */if( (pHdr->eType&eType)==0 ){rc = 0;}}return rc;}/*** Return TRUE if the mask of type in eType matches no bits of the type of the** allocation p. Also return true if p==NULL.**** This routine is designed for use within an assert() statement, to** verify the type of an allocation. For example:**** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );*/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 ); /* Allocation is valid */if( (pHdr->eType&eType)!=0 ){rc = 0;}}return rc;}/*** Set the number of backtrace levels kept for each allocation.** A value of zero turns off backtracing. The number is always rounded** up to a multiple of 2.*/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;}/*** Set the title string for subsequent allocations.*/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]);}}/*** Open the file indicated and write a log of all unfreed memory** allocations into that log.*/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);}/*** Return the number of times sqlite3MemMalloc() has been called.*/int sqlite3MemdebugMallocCount(){int i;int nTotal = 0;for(i=0; i<NCSIZE; i++){nTotal += mem.nAlloc[i];}return nTotal;}#endif /* SQLITE_MEMDEBUG */
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。