xref: /sqlite-3.40.0/src/mem2.c (revision fec00eab)
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