diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/malloc.c | 16 | ||||
-rw-r--r-- | src/mem2.c | 45 | ||||
-rw-r--r-- | src/pcache1.c | 6 | ||||
-rw-r--r-- | src/sqliteInt.h | 39 |
4 files changed, 104 insertions, 2 deletions
diff --git a/src/malloc.c b/src/malloc.c index 6b251876d..6d3b3002e 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -356,6 +356,7 @@ scratch_overflow: }else{ p = sqlite3GlobalConfig.m.xMalloc(n); } + sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH); #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) scratchAllocOut = p!=0; #endif @@ -376,6 +377,8 @@ void sqlite3ScratchFree(void *p){ if( sqlite3GlobalConfig.pScratch==0 || p<sqlite3GlobalConfig.pScratch || p>=(void*)mem0.aScratchFree ){ + assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); if( sqlite3GlobalConfig.bMemstat ){ int iSize = sqlite3MallocSize(p); sqlite3_mutex_enter(mem0.mutex); @@ -416,6 +419,7 @@ static int isLookaside(sqlite3 *db, void *p){ ** sqlite3Malloc() or sqlite3_malloc(). */ int sqlite3MallocSize(void *p){ + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3GlobalConfig.m.xSize(p); } int sqlite3DbMallocSize(sqlite3 *db, void *p){ @@ -423,6 +427,8 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){ if( isLookaside(db, p) ){ return db->lookaside.sz; }else{ + assert( sqlite3MemdebugHasType(p, + db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) ); return sqlite3GlobalConfig.m.xSize(p); } } @@ -432,6 +438,7 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){ */ void sqlite3_free(void *p){ if( p==0 ) return; + assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p)); @@ -454,6 +461,8 @@ void sqlite3DbFree(sqlite3 *db, void *p){ db->lookaside.pFree = pBuf; db->lookaside.nOut--; }else{ + assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3_free(p); } } @@ -486,6 +495,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){ mem0.alarmThreshold ){ sqlite3MallocAlarm(nNew-nOld); } + assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmCallback ){ sqlite3MallocAlarm(nBytes); @@ -583,6 +593,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){ if( !p && db ){ db->mallocFailed = 1; } + sqlite3MemdebugSetType(p, + (db && db->lookaside.bEnabled) ? MEMTYPE_DB : MEMTYPE_HEAP); return p; } @@ -608,10 +620,14 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){ sqlite3DbFree(db, p); } }else{ + assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3_realloc(p, n); if( !pNew ){ db->mallocFailed = 1; } + sqlite3MemdebugSetType(pNew, + db->lookaside.bEnabled ? MEMTYPE_DB : MEMTYPE_HEAP); } } return pNew; diff --git a/src/mem2.c b/src/mem2.c index 5eb937ed4..a82fee8fd 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -57,7 +57,8 @@ struct MemBlockHdr { struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ char nBacktrace; /* Number of backtraces on this alloc */ char nBacktraceSlots; /* Available backtrace slots */ - short nTitle; /* Bytes of title; includes '\0' */ + u8 nTitle; /* Bytes of title; includes '\0' */ + u8 eType; /* Allocation type code */ int iForeGuard; /* Guard word for sanity */ }; @@ -265,6 +266,7 @@ static void *sqlite3MemMalloc(int nByte){ } mem.pLast = pHdr; pHdr->iForeGuard = FOREGUARD; + pHdr->eType = MEMTYPE_HEAP; pHdr->nBacktraceSlots = mem.nBacktrace; pHdr->nTitle = mem.nTitle; if( mem.nBacktrace ){ @@ -373,6 +375,47 @@ void sqlite3MemSetDefault(void){ } /* +** Set the "type" of an allocation. +*/ +void sqlite3MemdebugSetType(void *p, u8 eType){ + if( p ){ + 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_DB) ); +*/ +int sqlite3MemdebugHasType(void *p, u8 eType){ + int rc = 1; + if( p ){ + struct MemBlockHdr *pHdr; + pHdr = sqlite3MemsysGetHeader(p); + assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */ + assert( (pHdr->eType & (pHdr->eType-1))==0 ); /* Only one type bit set */ + if( (pHdr->eType&eType)==0 ){ + void **pBt; + pBt = (void**)pHdr; + pBt -= pHdr->nBacktraceSlots; + backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(stderr)); + fprintf(stderr, "\n"); + 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. diff --git a/src/pcache1.c b/src/pcache1.c index a3bd0fcea..92cf5adb9 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -173,6 +173,7 @@ static void *pcache1Alloc(int nByte){ int sz = sqlite3MallocSize(p); sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); } + sqlite3MemdebugSetType(p, MEMTYPE_PCACHE); } return p; } @@ -190,7 +191,10 @@ static void pcache1Free(void *p){ pSlot->pNext = pcache1.pFree; pcache1.pFree = pSlot; }else{ - int iSize = sqlite3MallocSize(p); + int iSize; + assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) ); + sqlite3MemdebugSetType(p, MEMTYPE_HEAP); + iSize = sqlite3MallocSize(p); sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize); sqlite3_free(p); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a21513d23..c674b71bd 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3089,4 +3089,43 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...); # define sqlite3VdbeIOTraceSql(X) #endif +/* +** These routines are available for the mem2.c debugging memory allocator +** only. They are used to verify that different "types" of memory +** allocations are properly tracked by the system. +** +** sqlite3MemdebugSetType() sets the "type" of an allocation to one of +** the MEMTYPE_* macros defined below. The type must be a bitmask with +** a single bit set. +** +** sqlite3MemdebugHasType() returns true if any of the bits in its second +** argument match the type set by the previous sqlite3MemdebugSetType(). +** sqlite3MemdebugHasType() is intended for use inside assert() statements. +** For example: +** +** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); +** +** Perhaps the most important point is the difference between MEMTYPE_HEAP +** and MEMTYPE_DB. If an allocation is MEMTYPE_DB, that means it might have +** been allocated by lookaside, except the allocation was too large or +** lookaside was already full. It is important to verify that allocations +** that might have been satisfied by lookaside are not passed back to +** non-lookaside free() routines. Asserts such as the example above are +** placed on the non-lookaside free() routines to verify this constraint. +** +** All of this is no-op for a production build. It only comes into +** play when the SQLITE_MEMDEBUG compile-time option is used. +*/ +#ifdef SQLITE_MEMDEBUG + void sqlite3MemdebugSetType(void*,u8); + int sqlite3MemdebugHasType(void*,u8); +#else +# define sqlite3MemdebugSetType(X,Y) /* no-op */ +# define sqlite3MemdebugHasType(X,Y) 1 #endif +#define MEMTYPE_HEAP 0x01 /* General heap allocations */ +#define MEMTYPE_DB 0x02 /* Associated with a database connection */ +#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */ +#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */ + +#endif /* _SQLITEINT_H_ */ |