Download src/mem2.c from AryaWu/sqlite: direct link, hf CLI and curl.
- Browser
- Download file 14.7 kB
-
https://huggingface.co/AryaWu/sqlite/resolve/main/src/mem2.c
- Command line
-
hf download hf://AryaWu/sqlite/src/mem2.c
-
curl -L -o mem2.c https://huggingface.co/AryaWu/sqlite/resolve/main/src/mem2.c
14.7 kB
| /* | |
| ** 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. | |
| */ | |
| /* | |
| ** This version of the memory allocator is used only if the | |
| ** SQLITE_MEMDEBUG macro is defined | |
| */ | |
| /* | |
| ** The backtrace functionality is only available with GLIBC | |
| */ | |
| extern int backtrace(void**,int); | |
| extern void backtrace_symbols_fd(void*const*,int,int); | |
| /* | |
| ** 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 | |
| */ | |
| /* | |
| ** Number of malloc size increments to track. | |
| */ | |
| /* | |
| ** 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; | |
| } | |