mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-12 13:01:09 +03:00
Improvements to memory leak detection. The --backtrace=NNN option is now
recognized by tester.tcl. Memory leak summaries are automatically written to the file ./memleak.txt and each leak is tagged with the test in which it occurred. The quick.test script runs on Linux with no errors and no leaks. (CVS 4273) FossilOrigin-Name: 21f6b31097692171c6493e6ca6de6acbd62dc595
This commit is contained in:
58
src/mem2.c
58
src/mem2.c
@@ -12,7 +12,7 @@
|
||||
** This file contains the C functions that implement a memory
|
||||
** allocation subsystem for use by SQLite.
|
||||
**
|
||||
** $Id: mem2.c,v 1.7 2007/08/22 22:04:37 drh Exp $
|
||||
** $Id: mem2.c,v 1.8 2007/08/23 02:47:53 drh Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -59,9 +59,9 @@
|
||||
/*
|
||||
** Each memory allocation looks like this:
|
||||
**
|
||||
** ----------------------------------------------------------------
|
||||
** | backtrace pointers | MemBlockHdr | allocation | EndGuard |
|
||||
** ----------------------------------------------------------------
|
||||
** ------------------------------------------------------------------------
|
||||
** | 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
|
||||
@@ -72,8 +72,9 @@
|
||||
struct MemBlockHdr {
|
||||
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
|
||||
unsigned int iSize; /* Size of this allocation */
|
||||
unsigned short nBacktrace; /* Number of backtraces on this alloc */
|
||||
unsigned short nBacktraceSlots; /* Available backtrace slots */
|
||||
unsigned char nBacktrace; /* Number of backtraces on this alloc */
|
||||
unsigned char nBacktraceSlots; /* Available backtrace slots */
|
||||
unsigned short nTitle; /* Bytes of title; includes '\0' */
|
||||
unsigned int iForeGuard; /* Guard word for sanity */
|
||||
};
|
||||
|
||||
@@ -124,6 +125,12 @@ static struct {
|
||||
*/
|
||||
int nBacktrace;
|
||||
|
||||
/*
|
||||
** 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 */
|
||||
|
||||
/*
|
||||
** These values are used to simulate malloc failures. When
|
||||
** iFail is 1, simulate a malloc failures and reset the value
|
||||
@@ -252,6 +259,7 @@ static void sqlite3MemsysFailed(void){
|
||||
void *sqlite3_malloc(int nByte){
|
||||
struct MemBlockHdr *pHdr;
|
||||
void **pBt;
|
||||
char *z;
|
||||
unsigned int *pInt;
|
||||
void *p;
|
||||
unsigned int totalSize;
|
||||
@@ -269,7 +277,7 @@ void *sqlite3_malloc(int nByte){
|
||||
}
|
||||
nByte = (nByte+3)&~3;
|
||||
totalSize = nByte + sizeof(*pHdr) + sizeof(unsigned int) +
|
||||
mem.nBacktrace*sizeof(void*);
|
||||
mem.nBacktrace*sizeof(void*) + mem.nTitle;
|
||||
if( mem.iFail>0 ){
|
||||
if( mem.iFail==1 ){
|
||||
p = 0;
|
||||
@@ -290,7 +298,8 @@ void *sqlite3_malloc(int nByte){
|
||||
}
|
||||
}
|
||||
if( p ){
|
||||
pBt = p;
|
||||
z = p;
|
||||
pBt = (void**)&z[mem.nTitle];
|
||||
pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace];
|
||||
pHdr->pNext = 0;
|
||||
pHdr->pPrev = mem.pLast;
|
||||
@@ -302,6 +311,7 @@ void *sqlite3_malloc(int nByte){
|
||||
mem.pLast = pHdr;
|
||||
pHdr->iForeGuard = FOREGUARD;
|
||||
pHdr->nBacktraceSlots = mem.nBacktrace;
|
||||
pHdr->nTitle = mem.nTitle;
|
||||
if( mem.nBacktrace ){
|
||||
void *aAddr[40];
|
||||
pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1;
|
||||
@@ -309,6 +319,9 @@ void *sqlite3_malloc(int nByte){
|
||||
}else{
|
||||
pHdr->nBacktrace = 0;
|
||||
}
|
||||
if( mem.nTitle ){
|
||||
memcpy(z, mem.zTitle, mem.nTitle);
|
||||
}
|
||||
pHdr->iSize = nByte;
|
||||
pInt = (unsigned int *)&pHdr[1];
|
||||
pInt[nByte/sizeof(unsigned int)] = REARGUARD;
|
||||
@@ -329,6 +342,7 @@ void *sqlite3_malloc(int nByte){
|
||||
void sqlite3_free(void *pPrior){
|
||||
struct MemBlockHdr *pHdr;
|
||||
void **pBt;
|
||||
char *z;
|
||||
if( pPrior==0 ){
|
||||
return;
|
||||
}
|
||||
@@ -352,9 +366,11 @@ void sqlite3_free(void *pPrior){
|
||||
assert( mem.pLast==pHdr );
|
||||
mem.pLast = pHdr->pPrev;
|
||||
}
|
||||
memset(pBt, 0x2b, sizeof(void*)*pHdr->nBacktrace + sizeof(*pHdr) +
|
||||
pHdr->iSize + sizeof(unsigned int));
|
||||
free(pBt);
|
||||
z = (char*)pBt;
|
||||
z -= pHdr->nTitle;
|
||||
memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
|
||||
pHdr->iSize + sizeof(unsigned int) + pHdr->nTitle);
|
||||
free(z);
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
|
||||
@@ -402,6 +418,22 @@ void sqlite3_memdebug_backtrace(int depth){
|
||||
mem.nBacktrace = depth;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the title string for subsequent allocations.
|
||||
*/
|
||||
void sqlite3_memdebug_settitle(const char *zTitle){
|
||||
int n = strlen(zTitle) + 1;
|
||||
if( mem.mutex==0 ){
|
||||
mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
|
||||
}
|
||||
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 = (n+3)&~3;
|
||||
sqlite3_mutex_leave(mem.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open the file indicated and write a log of all unfreed memory
|
||||
** allocations into that log.
|
||||
@@ -417,7 +449,9 @@ void sqlite3_memdebug_dump(const char *zFilename){
|
||||
return;
|
||||
}
|
||||
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
|
||||
fprintf(out, "**** %d bytes at %p ****\n", pHdr->iSize, &pHdr[1]);
|
||||
char *z = (char*)pHdr;
|
||||
z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
|
||||
fprintf(out, "**** %d bytes at %p from %s ****\n", pHdr->iSize,&pHdr[1],z);
|
||||
if( pHdr->nBacktrace ){
|
||||
fflush(out);
|
||||
pBt = (void**)pHdr;
|
||||
|
||||
Reference in New Issue
Block a user