aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/malloc.c16
-rw-r--r--src/mem2.c45
-rw-r--r--src/pcache1.c6
-rw-r--r--src/sqliteInt.h39
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_ */