14c3645c6Sdrh /* 24c3645c6Sdrh ** 2007 August 15 34c3645c6Sdrh ** 44c3645c6Sdrh ** The author disclaims copyright to this source code. In place of 54c3645c6Sdrh ** a legal notice, here is a blessing: 64c3645c6Sdrh ** 74c3645c6Sdrh ** May you do good and not evil. 84c3645c6Sdrh ** May you find forgiveness for yourself and forgive others. 94c3645c6Sdrh ** May you share freely, never taking more than you give. 104c3645c6Sdrh ** 114c3645c6Sdrh ************************************************************************* 124c3645c6Sdrh ** 13*fec00eabSdrh ** This file contains low-level memory allocation drivers for when 14*fec00eabSdrh ** SQLite will use the standard C-library malloc/realloc/free interface 15*fec00eabSdrh ** to obtain the memory it needs while adding lots of additional debugging 16*fec00eabSdrh ** information to each allocation in order to help detect and fix memory 17*fec00eabSdrh ** leaks and memory usage errors. 18*fec00eabSdrh ** 19*fec00eabSdrh ** This file contains implementations of the low-level memory allocation 20*fec00eabSdrh ** routines specified in the sqlite3_mem_methods object. 21*fec00eabSdrh ** 22*fec00eabSdrh ** $Id: mem2.c,v 1.28 2008/06/14 16:56:22 drh Exp $ 234c3645c6Sdrh */ 240d18020bSdrh #include "sqliteInt.h" 254c3645c6Sdrh 264c3645c6Sdrh /* 274c3645c6Sdrh ** This version of the memory allocator is used only if the 280d18020bSdrh ** SQLITE_MEMDEBUG macro is defined 294c3645c6Sdrh */ 300d18020bSdrh #ifdef SQLITE_MEMDEBUG 314c3645c6Sdrh 324c3645c6Sdrh /* 334c3645c6Sdrh ** The backtrace functionality is only available with GLIBC 344c3645c6Sdrh */ 354c3645c6Sdrh #ifdef __GLIBC__ 364c3645c6Sdrh extern int backtrace(void**,int); 374c3645c6Sdrh extern void backtrace_symbols_fd(void*const*,int,int); 384c3645c6Sdrh #else 394c3645c6Sdrh # define backtrace(A,B) 0 404c3645c6Sdrh # define backtrace_symbols_fd(A,B,C) 414c3645c6Sdrh #endif 420d18020bSdrh #include <stdio.h> 434c3645c6Sdrh 444c3645c6Sdrh /* 454c3645c6Sdrh ** Each memory allocation looks like this: 464c3645c6Sdrh ** 474a50aac5Sdrh ** ------------------------------------------------------------------------ 484a50aac5Sdrh ** | Title | backtrace pointers | MemBlockHdr | allocation | EndGuard | 494a50aac5Sdrh ** ------------------------------------------------------------------------ 504c3645c6Sdrh ** 514c3645c6Sdrh ** The application code sees only a pointer to the allocation. We have 524c3645c6Sdrh ** to back up from the allocation pointer to find the MemBlockHdr. The 534c3645c6Sdrh ** MemBlockHdr tells us the size of the allocation and the number of 544c3645c6Sdrh ** backtrace pointers. There is also a guard word at the end of the 554c3645c6Sdrh ** MemBlockHdr. 564c3645c6Sdrh */ 574c3645c6Sdrh struct MemBlockHdr { 58fab69597Sdrh i64 iSize; /* Size of this allocation */ 594c3645c6Sdrh struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */ 60153c62c4Sdrh char nBacktrace; /* Number of backtraces on this alloc */ 61153c62c4Sdrh char nBacktraceSlots; /* Available backtrace slots */ 62153c62c4Sdrh short nTitle; /* Bytes of title; includes '\0' */ 63153c62c4Sdrh int iForeGuard; /* Guard word for sanity */ 644c3645c6Sdrh }; 654c3645c6Sdrh 664c3645c6Sdrh /* 674c3645c6Sdrh ** Guard words 684c3645c6Sdrh */ 694c3645c6Sdrh #define FOREGUARD 0x80F5E153 704c3645c6Sdrh #define REARGUARD 0xE4676B53 714c3645c6Sdrh 724c3645c6Sdrh /* 73d2bb3278Sdrh ** Number of malloc size increments to track. 74d2bb3278Sdrh */ 759c7a60dfSdrh #define NCSIZE 1000 76d2bb3278Sdrh 77d2bb3278Sdrh /* 780e6f1546Sdrh ** All of the static variables used by this module are collected 790e6f1546Sdrh ** into a single structure named "mem". This is to keep the 800e6f1546Sdrh ** static variables organized and to reduce namespace pollution 810e6f1546Sdrh ** when this module is combined with other in the amalgamation. 820e6f1546Sdrh */ 830e6f1546Sdrh static struct { 840e6f1546Sdrh 850e6f1546Sdrh /* 860e6f1546Sdrh ** Mutex to control access to the memory allocation subsystem. 870e6f1546Sdrh */ 880e6f1546Sdrh sqlite3_mutex *mutex; 890e6f1546Sdrh 900e6f1546Sdrh /* 914c3645c6Sdrh ** Head and tail of a linked list of all outstanding allocations 924c3645c6Sdrh */ 930e6f1546Sdrh struct MemBlockHdr *pFirst; 940e6f1546Sdrh struct MemBlockHdr *pLast; 954c3645c6Sdrh 964c3645c6Sdrh /* 974c3645c6Sdrh ** The number of levels of backtrace to save in new allocations. 984c3645c6Sdrh */ 990e6f1546Sdrh int nBacktrace; 1006f332c18Sdanielk1977 void (*xBacktrace)(int, int, void **); 1010e6f1546Sdrh 1020e6f1546Sdrh /* 1034a50aac5Sdrh ** Title text to insert in front of each block 1044a50aac5Sdrh */ 1054a50aac5Sdrh int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ 1064a50aac5Sdrh char zTitle[100]; /* The title text */ 1074a50aac5Sdrh 1084a50aac5Sdrh /* 109d677b3d6Sdrh ** sqlite3MallocDisallow() increments the following counter. 110d677b3d6Sdrh ** sqlite3MallocAllow() decrements it. 111d677b3d6Sdrh */ 112d677b3d6Sdrh int disallow; /* Do not allow memory allocation */ 113d677b3d6Sdrh 114d2bb3278Sdrh /* 115d2bb3278Sdrh ** Gather statistics on the sizes of memory allocations. 1169c7a60dfSdrh ** sizeCnt[i] is the number of allocation attempts of i*8 117d2bb3278Sdrh ** bytes. i==NCSIZE is the number of allocation attempts for 1189c7a60dfSdrh ** sizes more than NCSIZE*8 bytes. 119d2bb3278Sdrh */ 120d2bb3278Sdrh int sizeCnt[NCSIZE]; 1210e6f1546Sdrh 122153c62c4Sdrh } mem; 1230e6f1546Sdrh 1244c3645c6Sdrh /* 1254c3645c6Sdrh ** Given an allocation, find the MemBlockHdr for that allocation. 1264c3645c6Sdrh ** 1274c3645c6Sdrh ** This routine checks the guards at either end of the allocation and 1284c3645c6Sdrh ** if they are incorrect it asserts. 1294c3645c6Sdrh */ 1304c3645c6Sdrh static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ 1314c3645c6Sdrh struct MemBlockHdr *p; 132153c62c4Sdrh int *pInt; 133ce98bba2Sdanielk1977 u8 *pU8; 134ce98bba2Sdanielk1977 int nReserve; 1354c3645c6Sdrh 1364c3645c6Sdrh p = (struct MemBlockHdr*)pAllocation; 1374c3645c6Sdrh p--; 1384c3645c6Sdrh assert( p->iForeGuard==FOREGUARD ); 139fab69597Sdrh nReserve = (p->iSize+7)&~7; 140153c62c4Sdrh pInt = (int*)pAllocation; 141ce98bba2Sdanielk1977 pU8 = (u8*)pAllocation; 142ce98bba2Sdanielk1977 assert( pInt[nReserve/sizeof(int)]==REARGUARD ); 143ce98bba2Sdanielk1977 assert( (nReserve-0)<=p->iSize || pU8[nReserve-1]==0x65 ); 144ce98bba2Sdanielk1977 assert( (nReserve-1)<=p->iSize || pU8[nReserve-2]==0x65 ); 145ce98bba2Sdanielk1977 assert( (nReserve-2)<=p->iSize || pU8[nReserve-3]==0x65 ); 1464c3645c6Sdrh return p; 1474c3645c6Sdrh } 1484c3645c6Sdrh 1494c3645c6Sdrh /* 150a7a8e14bSdanielk1977 ** Return the number of bytes currently allocated at address p. 151a7a8e14bSdanielk1977 */ 152*fec00eabSdrh static int sqlite3MemSize(void *p){ 153a7a8e14bSdanielk1977 struct MemBlockHdr *pHdr; 154a7a8e14bSdanielk1977 if( !p ){ 155a7a8e14bSdanielk1977 return 0; 156a7a8e14bSdanielk1977 } 157a7a8e14bSdanielk1977 pHdr = sqlite3MemsysGetHeader(p); 158a7a8e14bSdanielk1977 return pHdr->iSize; 159a7a8e14bSdanielk1977 } 160a7a8e14bSdanielk1977 161a7a8e14bSdanielk1977 /* 162*fec00eabSdrh ** Initialize the memory allocation subsystem. 16340257ffdSdrh */ 164*fec00eabSdrh static int sqlite3MemInit(void *NotUsed){ 165*fec00eabSdrh mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); 16640257ffdSdrh return SQLITE_OK; 16740257ffdSdrh } 16840257ffdSdrh 16940257ffdSdrh /* 170*fec00eabSdrh ** Deinitialize the memory allocation subsystem. 171*fec00eabSdrh */ 172*fec00eabSdrh static void sqlite3MemShutdown(void *NotUsed){ 173*fec00eabSdrh sqlite3_mutex_free(mem.mutex); 174*fec00eabSdrh mem.mutex = 0; 175*fec00eabSdrh } 176*fec00eabSdrh 177*fec00eabSdrh /* 178*fec00eabSdrh ** Round up a request size to the next valid allocation size. 179*fec00eabSdrh */ 180*fec00eabSdrh static int sqlite3MemRoundup(int n){ 181*fec00eabSdrh return (n+7) & ~7; 182*fec00eabSdrh } 183*fec00eabSdrh 184*fec00eabSdrh /* 1850e6f1546Sdrh ** Allocate nByte bytes of memory. 1864c3645c6Sdrh */ 187*fec00eabSdrh static void *sqlite3MemMalloc(int nByte){ 1884c3645c6Sdrh struct MemBlockHdr *pHdr; 1894c3645c6Sdrh void **pBt; 1904a50aac5Sdrh char *z; 191153c62c4Sdrh int *pInt; 192ca0c8971Sdanielk1977 void *p = 0; 193153c62c4Sdrh int totalSize; 194ce98bba2Sdanielk1977 int nReserve; 195*fec00eabSdrh sqlite3_mutex_enter(mem.mutex); 196d677b3d6Sdrh assert( mem.disallow==0 ); 197fab69597Sdrh nReserve = (nByte+7)&~7; 198ce98bba2Sdanielk1977 if( nReserve/8>NCSIZE-1 ){ 199d2bb3278Sdrh mem.sizeCnt[NCSIZE-1]++; 200d2bb3278Sdrh }else{ 201ce98bba2Sdanielk1977 mem.sizeCnt[nReserve/8]++; 202d2bb3278Sdrh } 203ce98bba2Sdanielk1977 totalSize = nReserve + sizeof(*pHdr) + sizeof(int) + 2044a50aac5Sdrh mem.nBacktrace*sizeof(void*) + mem.nTitle; 2054c3645c6Sdrh p = malloc(totalSize); 2064c3645c6Sdrh if( p ){ 2074a50aac5Sdrh z = p; 2084a50aac5Sdrh pBt = (void**)&z[mem.nTitle]; 2090e6f1546Sdrh pHdr = (struct MemBlockHdr*)&pBt[mem.nBacktrace]; 2104c3645c6Sdrh pHdr->pNext = 0; 2110e6f1546Sdrh pHdr->pPrev = mem.pLast; 2120e6f1546Sdrh if( mem.pLast ){ 2130e6f1546Sdrh mem.pLast->pNext = pHdr; 2144c3645c6Sdrh }else{ 2150e6f1546Sdrh mem.pFirst = pHdr; 2164c3645c6Sdrh } 2170e6f1546Sdrh mem.pLast = pHdr; 2184c3645c6Sdrh pHdr->iForeGuard = FOREGUARD; 2190e6f1546Sdrh pHdr->nBacktraceSlots = mem.nBacktrace; 2204a50aac5Sdrh pHdr->nTitle = mem.nTitle; 2210e6f1546Sdrh if( mem.nBacktrace ){ 2222f999a67Sdrh void *aAddr[40]; 2230e6f1546Sdrh pHdr->nBacktrace = backtrace(aAddr, mem.nBacktrace+1)-1; 2242f999a67Sdrh memcpy(pBt, &aAddr[1], pHdr->nBacktrace*sizeof(void*)); 2256f332c18Sdanielk1977 if( mem.xBacktrace ){ 2266f332c18Sdanielk1977 mem.xBacktrace(nByte, pHdr->nBacktrace-1, &aAddr[1]); 2276f332c18Sdanielk1977 } 2284c3645c6Sdrh }else{ 2294c3645c6Sdrh pHdr->nBacktrace = 0; 2304c3645c6Sdrh } 2314a50aac5Sdrh if( mem.nTitle ){ 2324a50aac5Sdrh memcpy(z, mem.zTitle, mem.nTitle); 2334a50aac5Sdrh } 2344c3645c6Sdrh pHdr->iSize = nByte; 235153c62c4Sdrh pInt = (int*)&pHdr[1]; 236ce98bba2Sdanielk1977 pInt[nReserve/sizeof(int)] = REARGUARD; 237ce98bba2Sdanielk1977 memset(pInt, 0x65, nReserve); 2384c3645c6Sdrh p = (void*)pInt; 2394c3645c6Sdrh } 2400e6f1546Sdrh sqlite3_mutex_leave(mem.mutex); 2414c3645c6Sdrh return p; 2424c3645c6Sdrh } 2434c3645c6Sdrh 2444c3645c6Sdrh /* 2454c3645c6Sdrh ** Free memory. 2464c3645c6Sdrh */ 247*fec00eabSdrh static void sqlite3MemFree(void *pPrior){ 2484c3645c6Sdrh struct MemBlockHdr *pHdr; 2494c3645c6Sdrh void **pBt; 2504a50aac5Sdrh char *z; 2510e6f1546Sdrh assert( mem.mutex!=0 ); 2524c3645c6Sdrh pHdr = sqlite3MemsysGetHeader(pPrior); 2534c3645c6Sdrh pBt = (void**)pHdr; 2544c3645c6Sdrh pBt -= pHdr->nBacktraceSlots; 2556bdec4afSdrh sqlite3_mutex_enter(mem.mutex); 2564c3645c6Sdrh if( pHdr->pPrev ){ 2574c3645c6Sdrh assert( pHdr->pPrev->pNext==pHdr ); 2584c3645c6Sdrh pHdr->pPrev->pNext = pHdr->pNext; 2594c3645c6Sdrh }else{ 2600e6f1546Sdrh assert( mem.pFirst==pHdr ); 2610e6f1546Sdrh mem.pFirst = pHdr->pNext; 2624c3645c6Sdrh } 2634c3645c6Sdrh if( pHdr->pNext ){ 2644c3645c6Sdrh assert( pHdr->pNext->pPrev==pHdr ); 2654c3645c6Sdrh pHdr->pNext->pPrev = pHdr->pPrev; 2664c3645c6Sdrh }else{ 2670e6f1546Sdrh assert( mem.pLast==pHdr ); 2680e6f1546Sdrh mem.pLast = pHdr->pPrev; 2694c3645c6Sdrh } 2704a50aac5Sdrh z = (char*)pBt; 2714a50aac5Sdrh z -= pHdr->nTitle; 2724a50aac5Sdrh memset(z, 0x2b, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) + 273153c62c4Sdrh pHdr->iSize + sizeof(int) + pHdr->nTitle); 2744a50aac5Sdrh free(z); 2750e6f1546Sdrh sqlite3_mutex_leave(mem.mutex); 2764c3645c6Sdrh } 2774c3645c6Sdrh 2784c3645c6Sdrh /* 2794c3645c6Sdrh ** Change the size of an existing memory allocation. 2804c3645c6Sdrh ** 2814c3645c6Sdrh ** For this debugging implementation, we *always* make a copy of the 2824c3645c6Sdrh ** allocation into a new place in memory. In this way, if the 2834c3645c6Sdrh ** higher level code is using pointer to the old allocation, it is 2844c3645c6Sdrh ** much more likely to break and we are much more liking to find 2854c3645c6Sdrh ** the error. 2864c3645c6Sdrh */ 287*fec00eabSdrh static void *sqlite3MemRealloc(void *pPrior, int nByte){ 2884c3645c6Sdrh struct MemBlockHdr *pOldHdr; 2894c3645c6Sdrh void *pNew; 290d677b3d6Sdrh assert( mem.disallow==0 ); 2914c3645c6Sdrh pOldHdr = sqlite3MemsysGetHeader(pPrior); 292*fec00eabSdrh pNew = sqlite3MemMalloc(nByte); 2934c3645c6Sdrh if( pNew ){ 2944c3645c6Sdrh memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize); 2954c3645c6Sdrh if( nByte>pOldHdr->iSize ){ 2964c3645c6Sdrh memset(&((char*)pNew)[pOldHdr->iSize], 0x2b, nByte - pOldHdr->iSize); 2974c3645c6Sdrh } 298*fec00eabSdrh sqlite3MemFree(pPrior); 2994c3645c6Sdrh } 3004c3645c6Sdrh return pNew; 3014c3645c6Sdrh } 3024c3645c6Sdrh 303*fec00eabSdrh 304*fec00eabSdrh /* 305*fec00eabSdrh ** Populate the low-level memory allocation function pointers in 306*fec00eabSdrh ** sqlite3Config.m with pointers to the routines in this file. 307*fec00eabSdrh */ 308*fec00eabSdrh void sqlite3MemSetDefault(void){ 309*fec00eabSdrh static const sqlite3_mem_methods defaultMethods = { 310*fec00eabSdrh sqlite3MemMalloc, 311*fec00eabSdrh sqlite3MemFree, 312*fec00eabSdrh sqlite3MemRealloc, 313*fec00eabSdrh sqlite3MemSize, 314*fec00eabSdrh sqlite3MemRoundup, 315*fec00eabSdrh sqlite3MemInit, 316*fec00eabSdrh sqlite3MemShutdown, 317*fec00eabSdrh 0 318*fec00eabSdrh }; 319*fec00eabSdrh sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods); 320*fec00eabSdrh } 321*fec00eabSdrh 3224c3645c6Sdrh /* 3234c3645c6Sdrh ** Set the number of backtrace levels kept for each allocation. 3244c3645c6Sdrh ** A value of zero turns of backtracing. The number is always rounded 3254c3645c6Sdrh ** up to a multiple of 2. 3264c3645c6Sdrh */ 32749e4fd71Sdrh void sqlite3MemdebugBacktrace(int depth){ 3284c3645c6Sdrh if( depth<0 ){ depth = 0; } 3294c3645c6Sdrh if( depth>20 ){ depth = 20; } 3302f999a67Sdrh depth = (depth+1)&0xfe; 3310e6f1546Sdrh mem.nBacktrace = depth; 3324c3645c6Sdrh } 3334c3645c6Sdrh 3346f332c18Sdanielk1977 void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **)){ 3356f332c18Sdanielk1977 mem.xBacktrace = xBacktrace; 3366f332c18Sdanielk1977 } 3376f332c18Sdanielk1977 3384c3645c6Sdrh /* 3394a50aac5Sdrh ** Set the title string for subsequent allocations. 3404a50aac5Sdrh */ 34149e4fd71Sdrh void sqlite3MemdebugSettitle(const char *zTitle){ 3424a50aac5Sdrh int n = strlen(zTitle) + 1; 343*fec00eabSdrh sqlite3_mutex_enter(mem.mutex); 3444a50aac5Sdrh if( n>=sizeof(mem.zTitle) ) n = sizeof(mem.zTitle)-1; 3454a50aac5Sdrh memcpy(mem.zTitle, zTitle, n); 3464a50aac5Sdrh mem.zTitle[n] = 0; 347fab69597Sdrh mem.nTitle = (n+7)&~7; 3484a50aac5Sdrh sqlite3_mutex_leave(mem.mutex); 3494a50aac5Sdrh } 3504a50aac5Sdrh 351dbdc4d49Sdanielk1977 void sqlite3MemdebugSync(){ 352dbdc4d49Sdanielk1977 struct MemBlockHdr *pHdr; 353dbdc4d49Sdanielk1977 for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ 354dbdc4d49Sdanielk1977 void **pBt = (void**)pHdr; 355dbdc4d49Sdanielk1977 pBt -= pHdr->nBacktraceSlots; 356dbdc4d49Sdanielk1977 mem.xBacktrace(pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]); 357dbdc4d49Sdanielk1977 } 358dbdc4d49Sdanielk1977 } 359dbdc4d49Sdanielk1977 3604a50aac5Sdrh /* 3614c3645c6Sdrh ** Open the file indicated and write a log of all unfreed memory 3624c3645c6Sdrh ** allocations into that log. 3634c3645c6Sdrh */ 36449e4fd71Sdrh void sqlite3MemdebugDump(const char *zFilename){ 3654c3645c6Sdrh FILE *out; 3664c3645c6Sdrh struct MemBlockHdr *pHdr; 3674c3645c6Sdrh void **pBt; 368d2bb3278Sdrh int i; 3694c3645c6Sdrh out = fopen(zFilename, "w"); 3704c3645c6Sdrh if( out==0 ){ 3714c3645c6Sdrh fprintf(stderr, "** Unable to output memory debug output log: %s **\n", 3724c3645c6Sdrh zFilename); 3734c3645c6Sdrh return; 3744c3645c6Sdrh } 3750e6f1546Sdrh for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){ 3764a50aac5Sdrh char *z = (char*)pHdr; 3774a50aac5Sdrh z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle; 378fab69597Sdrh fprintf(out, "**** %lld bytes at %p from %s ****\n", 379d5499d64Sdrh pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???"); 3804c3645c6Sdrh if( pHdr->nBacktrace ){ 3814c3645c6Sdrh fflush(out); 3824c3645c6Sdrh pBt = (void**)pHdr; 3834c3645c6Sdrh pBt -= pHdr->nBacktraceSlots; 3844c3645c6Sdrh backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(out)); 3854c3645c6Sdrh fprintf(out, "\n"); 3864c3645c6Sdrh } 3874c3645c6Sdrh } 388d2bb3278Sdrh fprintf(out, "COUNTS:\n"); 389d2bb3278Sdrh for(i=0; i<NCSIZE-1; i++){ 390d2bb3278Sdrh if( mem.sizeCnt[i] ){ 391d2bb3278Sdrh fprintf(out, " %3d: %d\n", i*8+8, mem.sizeCnt[i]); 392d2bb3278Sdrh } 393d2bb3278Sdrh } 394d2bb3278Sdrh if( mem.sizeCnt[NCSIZE-1] ){ 395d2bb3278Sdrh fprintf(out, " >%3d: %d\n", NCSIZE*8, mem.sizeCnt[NCSIZE-1]); 396d2bb3278Sdrh } 3974c3645c6Sdrh fclose(out); 3984c3645c6Sdrh } 3994c3645c6Sdrh 400a7a8e14bSdanielk1977 /* 401*fec00eabSdrh ** Return the number of times sqlite3MemMalloc() has been called. 402a7a8e14bSdanielk1977 */ 40349e4fd71Sdrh int sqlite3MemdebugMallocCount(){ 404a7a8e14bSdanielk1977 int i; 405a7a8e14bSdanielk1977 int nTotal = 0; 406a7a8e14bSdanielk1977 for(i=0; i<NCSIZE; i++){ 407a7a8e14bSdanielk1977 nTotal += mem.sizeCnt[i]; 408a7a8e14bSdanielk1977 } 409a7a8e14bSdanielk1977 return nTotal; 410a7a8e14bSdanielk1977 } 411a7a8e14bSdanielk1977 412d677b3d6Sdrh 4130d18020bSdrh #endif /* SQLITE_MEMDEBUG */ 414