xref: /sqlite-3.40.0/src/test_malloc.c (revision 7fdb522c)
1 /*
2 ** 2007 August 15
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** This file contains code used to implement test interfaces to the
14 ** memory allocation subsystem.
15 **
16 ** $Id: test_malloc.c,v 1.43 2008/07/29 14:29:07 drh Exp $
17 */
18 #include "sqliteInt.h"
19 #include "tcl.h"
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 
24 /*
25 ** This structure is used to encapsulate the global state variables used
26 ** by malloc() fault simulation.
27 */
28 static struct MemFault {
29   int iCountdown;         /* Number of pending successes before a failure */
30   int nRepeat;            /* Number of times to repeat the failure */
31   int nBenign;            /* Number of benign failures seen since last config */
32   int nFail;              /* Number of failures seen since last config */
33   u8 enable;              /* True if enabled */
34   int isInstalled;        /* True if the fault simulation layer is installed */
35   int isBenignMode;       /* True if malloc failures are considered benign */
36   sqlite3_mem_methods m;  /* 'Real' malloc implementation */
37 } memfault;
38 
39 /*
40 ** This routine exists as a place to set a breakpoint that will
41 ** fire on any simulated malloc() failure.
42 */
43 static void sqlite3Fault(void){
44   static int cnt = 0;
45   cnt++;
46 }
47 
48 /*
49 ** Check to see if a fault should be simulated.  Return true to simulate
50 ** the fault.  Return false if the fault should not be simulated.
51 */
52 static int faultsimStep(){
53   if( likely(!memfault.enable) ){
54     return 0;
55   }
56   if( memfault.iCountdown>0 ){
57     memfault.iCountdown--;
58     return 0;
59   }
60   sqlite3Fault();
61   memfault.nFail++;
62   if( memfault.isBenignMode>0 ){
63     memfault.nBenign++;
64   }
65   memfault.nRepeat--;
66   if( memfault.nRepeat<=0 ){
67     memfault.enable = 0;
68   }
69   return 1;
70 }
71 
72 /*
73 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
74 ** logic.
75 */
76 static void *faultsimMalloc(int n){
77   void *p = 0;
78   if( !faultsimStep() ){
79     p = memfault.m.xMalloc(n);
80   }
81   return p;
82 }
83 
84 
85 /*
86 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
87 ** logic.
88 */
89 static void *faultsimRealloc(void *pOld, int n){
90   void *p = 0;
91   if( !faultsimStep() ){
92     p = memfault.m.xRealloc(pOld, n);
93   }
94   return p;
95 }
96 
97 /*
98 ** The following method calls are passed directly through to the underlying
99 ** malloc system:
100 **
101 **     xFree
102 **     xSize
103 **     xRoundup
104 **     xInit
105 **     xShutdown
106 */
107 static void faultsimFree(void *p){
108   memfault.m.xFree(p);
109 }
110 static int faultsimSize(void *p){
111   return memfault.m.xSize(p);
112 }
113 static int faultsimRoundup(int n){
114   return memfault.m.xRoundup(n);
115 }
116 static int faultsimInit(void *p){
117   return memfault.m.xInit(memfault.m.pAppData);
118 }
119 static void faultsimShutdown(void *p){
120   memfault.m.xShutdown(memfault.m.pAppData);
121 }
122 
123 /*
124 ** This routine configures the malloc failure simulation.  After
125 ** calling this routine, the next nDelay mallocs will succeed, followed
126 ** by a block of nRepeat failures, after which malloc() calls will begin
127 ** to succeed again.
128 */
129 static void faultsimConfig(int nDelay, int nRepeat){
130   memfault.iCountdown = nDelay;
131   memfault.nRepeat = nRepeat;
132   memfault.nBenign = 0;
133   memfault.nFail = 0;
134   memfault.enable = nDelay>=0;
135 }
136 
137 /*
138 ** Return the number of faults (both hard and benign faults) that have
139 ** occurred since the injector was last configured.
140 */
141 static int faultsimFailures(void){
142   return memfault.nFail;
143 }
144 
145 /*
146 ** Return the number of benign faults that have occurred since the
147 ** injector was last configured.
148 */
149 static int faultsimBenignFailures(void){
150   return memfault.nBenign;
151 }
152 
153 /*
154 ** Return the number of successes that will occur before the next failure.
155 ** If no failures are scheduled, return -1.
156 */
157 static int faultsimPending(void){
158   if( memfault.enable ){
159     return memfault.iCountdown;
160   }else{
161     return -1;
162   }
163 }
164 
165 
166 static void faultsimBeginBenign(void){
167   memfault.isBenignMode++;
168 }
169 static void faultsimEndBenign(void){
170   memfault.isBenignMode--;
171 }
172 
173 /*
174 ** Add or remove the fault-simulation layer using sqlite3_config(). If
175 ** the argument is non-zero, the
176 */
177 static int faultsimInstall(int install){
178   static struct sqlite3_mem_methods m = {
179     faultsimMalloc,                   /* xMalloc */
180     faultsimFree,                     /* xFree */
181     faultsimRealloc,                  /* xRealloc */
182     faultsimSize,                     /* xSize */
183     faultsimRoundup,                  /* xRoundup */
184     faultsimInit,                     /* xInit */
185     faultsimShutdown,                 /* xShutdown */
186     0                                 /* pAppData */
187   };
188   int rc;
189 
190   install = (install ? 1 : 0);
191   assert(memfault.isInstalled==1 || memfault.isInstalled==0);
192 
193   if( install==memfault.isInstalled ){
194     return SQLITE_ERROR;
195   }
196 
197   if( install ){
198     rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
199     assert(memfault.m.xMalloc);
200     if( rc==SQLITE_OK ){
201       rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
202     }
203     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
204         faultsimBeginBenign, faultsimEndBenign
205     );
206   }else{
207     assert(memfault.m.xMalloc);
208     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
209     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
210   }
211 
212   if( rc==SQLITE_OK ){
213     memfault.isInstalled = 1;
214   }
215   return rc;
216 }
217 
218 #ifdef SQLITE_TEST
219 
220 /*
221 ** This function is implemented in test1.c. Returns a pointer to a static
222 ** buffer containing the symbolic SQLite error code that corresponds to
223 ** the least-significant 8-bits of the integer passed as an argument.
224 ** For example:
225 **
226 **   sqlite3TestErrorName(1) -> "SQLITE_ERROR"
227 */
228 const char *sqlite3TestErrorName(int);
229 
230 /*
231 ** Transform pointers to text and back again
232 */
233 static void pointerToText(void *p, char *z){
234   static const char zHex[] = "0123456789abcdef";
235   int i, k;
236   unsigned int u;
237   sqlite3_uint64 n;
238   if( p==0 ){
239     strcpy(z, "0");
240     return;
241   }
242   if( sizeof(n)==sizeof(p) ){
243     memcpy(&n, &p, sizeof(p));
244   }else if( sizeof(u)==sizeof(p) ){
245     memcpy(&u, &p, sizeof(u));
246     n = u;
247   }else{
248     assert( 0 );
249   }
250   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
251     z[k] = zHex[n&0xf];
252     n >>= 4;
253   }
254   z[sizeof(p)*2] = 0;
255 }
256 static int hexToInt(int h){
257   if( h>='0' && h<='9' ){
258     return h - '0';
259   }else if( h>='a' && h<='f' ){
260     return h - 'a' + 10;
261   }else{
262     return -1;
263   }
264 }
265 static int textToPointer(const char *z, void **pp){
266   sqlite3_uint64 n = 0;
267   int i;
268   unsigned int u;
269   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
270     int v;
271     v = hexToInt(*z++);
272     if( v<0 ) return TCL_ERROR;
273     n = n*16 + v;
274   }
275   if( *z!=0 ) return TCL_ERROR;
276   if( sizeof(n)==sizeof(*pp) ){
277     memcpy(pp, &n, sizeof(n));
278   }else if( sizeof(u)==sizeof(*pp) ){
279     u = (unsigned int)n;
280     memcpy(pp, &u, sizeof(u));
281   }else{
282     assert( 0 );
283   }
284   return TCL_OK;
285 }
286 
287 /*
288 ** Usage:    sqlite3_malloc  NBYTES
289 **
290 ** Raw test interface for sqlite3_malloc().
291 */
292 static int test_malloc(
293   void * clientData,
294   Tcl_Interp *interp,
295   int objc,
296   Tcl_Obj *CONST objv[]
297 ){
298   int nByte;
299   void *p;
300   char zOut[100];
301   if( objc!=2 ){
302     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
303     return TCL_ERROR;
304   }
305   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
306   p = sqlite3_malloc((unsigned)nByte);
307   pointerToText(p, zOut);
308   Tcl_AppendResult(interp, zOut, NULL);
309   return TCL_OK;
310 }
311 
312 /*
313 ** Usage:    sqlite3_realloc  PRIOR  NBYTES
314 **
315 ** Raw test interface for sqlite3_realloc().
316 */
317 static int test_realloc(
318   void * clientData,
319   Tcl_Interp *interp,
320   int objc,
321   Tcl_Obj *CONST objv[]
322 ){
323   int nByte;
324   void *pPrior, *p;
325   char zOut[100];
326   if( objc!=3 ){
327     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
328     return TCL_ERROR;
329   }
330   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
331   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
332     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
333     return TCL_ERROR;
334   }
335   p = sqlite3_realloc(pPrior, (unsigned)nByte);
336   pointerToText(p, zOut);
337   Tcl_AppendResult(interp, zOut, NULL);
338   return TCL_OK;
339 }
340 
341 /*
342 ** Usage:    sqlite3_free  PRIOR
343 **
344 ** Raw test interface for sqlite3_free().
345 */
346 static int test_free(
347   void * clientData,
348   Tcl_Interp *interp,
349   int objc,
350   Tcl_Obj *CONST objv[]
351 ){
352   void *pPrior;
353   if( objc!=2 ){
354     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
355     return TCL_ERROR;
356   }
357   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
358     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
359     return TCL_ERROR;
360   }
361   sqlite3_free(pPrior);
362   return TCL_OK;
363 }
364 
365 /*
366 ** These routines are in test_hexio.c
367 */
368 int sqlite3TestHexToBin(const char *, int, char *);
369 int sqlite3TestBinToHex(char*,int);
370 
371 /*
372 ** Usage:    memset  ADDRESS  SIZE  HEX
373 **
374 ** Set a chunk of memory (obtained from malloc, probably) to a
375 ** specified hex pattern.
376 */
377 static int test_memset(
378   void * clientData,
379   Tcl_Interp *interp,
380   int objc,
381   Tcl_Obj *CONST objv[]
382 ){
383   void *p;
384   int size, n, i;
385   char *zHex;
386   char *zOut;
387   char zBin[100];
388 
389   if( objc!=4 ){
390     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
391     return TCL_ERROR;
392   }
393   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
394     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
395     return TCL_ERROR;
396   }
397   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
398     return TCL_ERROR;
399   }
400   if( size<=0 ){
401     Tcl_AppendResult(interp, "size must be positive", (char*)0);
402     return TCL_ERROR;
403   }
404   zHex = Tcl_GetStringFromObj(objv[3], &n);
405   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
406   n = sqlite3TestHexToBin(zHex, n, zBin);
407   if( n==0 ){
408     Tcl_AppendResult(interp, "no data", (char*)0);
409     return TCL_ERROR;
410   }
411   zOut = p;
412   for(i=0; i<size; i++){
413     zOut[i] = zBin[i%n];
414   }
415   return TCL_OK;
416 }
417 
418 /*
419 ** Usage:    memget  ADDRESS  SIZE
420 **
421 ** Return memory as hexadecimal text.
422 */
423 static int test_memget(
424   void * clientData,
425   Tcl_Interp *interp,
426   int objc,
427   Tcl_Obj *CONST objv[]
428 ){
429   void *p;
430   int size, n;
431   char *zBin;
432   char zHex[100];
433 
434   if( objc!=3 ){
435     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
436     return TCL_ERROR;
437   }
438   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
439     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
440     return TCL_ERROR;
441   }
442   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
443     return TCL_ERROR;
444   }
445   if( size<=0 ){
446     Tcl_AppendResult(interp, "size must be positive", (char*)0);
447     return TCL_ERROR;
448   }
449   zBin = p;
450   while( size>0 ){
451     if( size>(sizeof(zHex)-1)/2 ){
452       n = (sizeof(zHex)-1)/2;
453     }else{
454       n = size;
455     }
456     memcpy(zHex, zBin, n);
457     zBin += n;
458     size -= n;
459     sqlite3TestBinToHex(zHex, n);
460     Tcl_AppendResult(interp, zHex, (char*)0);
461   }
462   return TCL_OK;
463 }
464 
465 /*
466 ** Usage:    sqlite3_memory_used
467 **
468 ** Raw test interface for sqlite3_memory_used().
469 */
470 static int test_memory_used(
471   void * clientData,
472   Tcl_Interp *interp,
473   int objc,
474   Tcl_Obj *CONST objv[]
475 ){
476   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
477   return TCL_OK;
478 }
479 
480 /*
481 ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
482 **
483 ** Raw test interface for sqlite3_memory_highwater().
484 */
485 static int test_memory_highwater(
486   void * clientData,
487   Tcl_Interp *interp,
488   int objc,
489   Tcl_Obj *CONST objv[]
490 ){
491   int resetFlag = 0;
492   if( objc!=1 && objc!=2 ){
493     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
494     return TCL_ERROR;
495   }
496   if( objc==2 ){
497     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
498   }
499   Tcl_SetObjResult(interp,
500      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
501   return TCL_OK;
502 }
503 
504 /*
505 ** Usage:    sqlite3_memdebug_backtrace DEPTH
506 **
507 ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
508 ** then this routine is a no-op.
509 */
510 static int test_memdebug_backtrace(
511   void * clientData,
512   Tcl_Interp *interp,
513   int objc,
514   Tcl_Obj *CONST objv[]
515 ){
516   int depth;
517   if( objc!=2 ){
518     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
519     return TCL_ERROR;
520   }
521   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
522 #ifdef SQLITE_MEMDEBUG
523   {
524     extern void sqlite3MemdebugBacktrace(int);
525     sqlite3MemdebugBacktrace(depth);
526   }
527 #endif
528   return TCL_OK;
529 }
530 
531 /*
532 ** Usage:    sqlite3_memdebug_dump  FILENAME
533 **
534 ** Write a summary of unfreed memory to FILENAME.
535 */
536 static int test_memdebug_dump(
537   void * clientData,
538   Tcl_Interp *interp,
539   int objc,
540   Tcl_Obj *CONST objv[]
541 ){
542   if( objc!=2 ){
543     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
544     return TCL_ERROR;
545   }
546 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
547      || defined(SQLITE_POW2_MEMORY_SIZE)
548   {
549     extern void sqlite3MemdebugDump(const char*);
550     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
551   }
552 #endif
553   return TCL_OK;
554 }
555 
556 /*
557 ** Usage:    sqlite3_memdebug_malloc_count
558 **
559 ** Return the total number of times malloc() has been called.
560 */
561 static int test_memdebug_malloc_count(
562   void * clientData,
563   Tcl_Interp *interp,
564   int objc,
565   Tcl_Obj *CONST objv[]
566 ){
567   int nMalloc = -1;
568   if( objc!=1 ){
569     Tcl_WrongNumArgs(interp, 1, objv, "");
570     return TCL_ERROR;
571   }
572 #if defined(SQLITE_MEMDEBUG)
573   {
574     extern int sqlite3MemdebugMallocCount();
575     nMalloc = sqlite3MemdebugMallocCount();
576   }
577 #endif
578   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
579   return TCL_OK;
580 }
581 
582 
583 /*
584 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
585 **
586 ** where options are:
587 **
588 **     -repeat    <count>
589 **     -benigncnt <varname>
590 **
591 ** Arrange for a simulated malloc() failure after COUNTER successes.
592 ** If a repeat count is specified, the fault is repeated that many
593 ** times.
594 **
595 ** Each call to this routine overrides the prior counter value.
596 ** This routine returns the number of simulated failures that have
597 ** happened since the previous call to this routine.
598 **
599 ** To disable simulated failures, use a COUNTER of -1.
600 */
601 static int test_memdebug_fail(
602   void * clientData,
603   Tcl_Interp *interp,
604   int objc,
605   Tcl_Obj *CONST objv[]
606 ){
607   int ii;
608   int iFail;
609   int nRepeat = 1;
610   Tcl_Obj *pBenignCnt = 0;
611   int nBenign;
612   int nFail = 0;
613 
614   if( objc<2 ){
615     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
616     return TCL_ERROR;
617   }
618   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
619 
620   for(ii=2; ii<objc; ii+=2){
621     int nOption;
622     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
623     char *zErr = 0;
624 
625     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
626       if( ii==(objc-1) ){
627         zErr = "option requires an argument: ";
628       }else{
629         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
630           return TCL_ERROR;
631         }
632       }
633     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
634       if( ii==(objc-1) ){
635         zErr = "option requires an argument: ";
636       }else{
637         pBenignCnt = objv[ii+1];
638       }
639     }else{
640       zErr = "unknown option: ";
641     }
642 
643     if( zErr ){
644       Tcl_AppendResult(interp, zErr, zOption, 0);
645       return TCL_ERROR;
646     }
647   }
648 
649   nBenign = faultsimBenignFailures();
650   nFail = faultsimFailures();
651   faultsimConfig(iFail, nRepeat);
652 
653   if( pBenignCnt ){
654     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
655   }
656   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
657   return TCL_OK;
658 }
659 
660 /*
661 ** Usage:    sqlite3_memdebug_pending
662 **
663 ** Return the number of malloc() calls that will succeed before a
664 ** simulated failure occurs. A negative return value indicates that
665 ** no malloc() failure is scheduled.
666 */
667 static int test_memdebug_pending(
668   void * clientData,
669   Tcl_Interp *interp,
670   int objc,
671   Tcl_Obj *CONST objv[]
672 ){
673   int nPending;
674   if( objc!=1 ){
675     Tcl_WrongNumArgs(interp, 1, objv, "");
676     return TCL_ERROR;
677   }
678   nPending = faultsimPending();
679   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
680   return TCL_OK;
681 }
682 
683 
684 /*
685 ** Usage:    sqlite3_memdebug_settitle TITLE
686 **
687 ** Set a title string stored with each allocation.  The TITLE is
688 ** typically the name of the test that was running when the
689 ** allocation occurred.  The TITLE is stored with the allocation
690 ** and can be used to figure out which tests are leaking memory.
691 **
692 ** Each title overwrite the previous.
693 */
694 static int test_memdebug_settitle(
695   void * clientData,
696   Tcl_Interp *interp,
697   int objc,
698   Tcl_Obj *CONST objv[]
699 ){
700   const char *zTitle;
701   if( objc!=2 ){
702     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
703     return TCL_ERROR;
704   }
705   zTitle = Tcl_GetString(objv[1]);
706 #ifdef SQLITE_MEMDEBUG
707   {
708     extern int sqlite3MemdebugSettitle(const char*);
709     sqlite3MemdebugSettitle(zTitle);
710   }
711 #endif
712   return TCL_OK;
713 }
714 
715 #define MALLOC_LOG_FRAMES 10
716 static Tcl_HashTable aMallocLog;
717 static int mallocLogEnabled = 0;
718 
719 typedef struct MallocLog MallocLog;
720 struct MallocLog {
721   int nCall;
722   int nByte;
723 };
724 
725 #ifdef SQLITE_MEMDEBUG
726 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
727   if( mallocLogEnabled ){
728     MallocLog *pLog;
729     Tcl_HashEntry *pEntry;
730     int isNew;
731 
732     int aKey[MALLOC_LOG_FRAMES];
733     int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
734 
735     memset(aKey, 0, nKey);
736     if( (sizeof(void*)*nFrame)<nKey ){
737       nKey = nFrame*sizeof(void*);
738     }
739     memcpy(aKey, aFrame, nKey);
740 
741     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
742     if( isNew ){
743       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
744       memset(pLog, 0, sizeof(MallocLog));
745       Tcl_SetHashValue(pEntry, (ClientData)pLog);
746     }else{
747       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
748     }
749 
750     pLog->nCall++;
751     pLog->nByte += nByte;
752   }
753 }
754 #endif /* SQLITE_MEMDEBUG */
755 
756 static void test_memdebug_log_clear(){
757   Tcl_HashSearch search;
758   Tcl_HashEntry *pEntry;
759   for(
760     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
761     pEntry;
762     pEntry=Tcl_NextHashEntry(&search)
763   ){
764     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
765     Tcl_Free((char *)pLog);
766   }
767   Tcl_DeleteHashTable(&aMallocLog);
768   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
769 }
770 
771 static int test_memdebug_log(
772   void * clientData,
773   Tcl_Interp *interp,
774   int objc,
775   Tcl_Obj *CONST objv[]
776 ){
777   static int isInit = 0;
778   int iSub;
779 
780   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
781   enum MB_enum {
782       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
783   };
784 
785   if( !isInit ){
786 #ifdef SQLITE_MEMDEBUG
787     extern void sqlite3MemdebugBacktraceCallback(
788         void (*xBacktrace)(int, int, void **));
789     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
790 #endif
791     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
792     isInit = 1;
793   }
794 
795   if( objc<2 ){
796     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
797   }
798   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
799     return TCL_ERROR;
800   }
801 
802   switch( (enum MB_enum)iSub ){
803     case MB_LOG_START:
804       mallocLogEnabled = 1;
805       break;
806     case MB_LOG_STOP:
807       mallocLogEnabled = 0;
808       break;
809     case MB_LOG_DUMP: {
810       Tcl_HashSearch search;
811       Tcl_HashEntry *pEntry;
812       Tcl_Obj *pRet = Tcl_NewObj();
813 
814       assert(sizeof(int)==sizeof(void*));
815 
816       for(
817         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
818         pEntry;
819         pEntry=Tcl_NextHashEntry(&search)
820       ){
821         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
822         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
823         int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
824         int ii;
825 
826         apElem[0] = Tcl_NewIntObj(pLog->nCall);
827         apElem[1] = Tcl_NewIntObj(pLog->nByte);
828         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
829           apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
830         }
831 
832         Tcl_ListObjAppendElement(interp, pRet,
833             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
834         );
835       }
836 
837       Tcl_SetObjResult(interp, pRet);
838       break;
839     }
840     case MB_LOG_CLEAR: {
841       test_memdebug_log_clear();
842       break;
843     }
844 
845     case MB_LOG_SYNC: {
846 #ifdef SQLITE_MEMDEBUG
847       extern void sqlite3MemdebugSync();
848       test_memdebug_log_clear();
849       mallocLogEnabled = 1;
850       sqlite3MemdebugSync();
851 #endif
852       break;
853     }
854   }
855 
856   return TCL_OK;
857 }
858 
859 /*
860 ** Usage:    sqlite3_config_scratch SIZE N
861 **
862 ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
863 ** The buffer is static and is of limited size.  N might be
864 ** adjusted downward as needed to accomodate the requested size.
865 ** The revised value of N is returned.
866 **
867 ** A negative SIZE causes the buffer pointer to be NULL.
868 */
869 static int test_config_scratch(
870   void * clientData,
871   Tcl_Interp *interp,
872   int objc,
873   Tcl_Obj *CONST objv[]
874 ){
875   int sz, N, rc;
876   Tcl_Obj *pResult;
877   static char *buf = 0;
878   if( objc!=3 ){
879     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
880     return TCL_ERROR;
881   }
882   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
883   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
884   free(buf);
885   if( sz<0 ){
886     buf = 0;
887     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
888   }else{
889     buf = malloc( (sz+4)*N );
890     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
891   }
892   pResult = Tcl_NewObj();
893   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
894   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
895   Tcl_SetObjResult(interp, pResult);
896   return TCL_OK;
897 }
898 
899 /*
900 ** Usage:    sqlite3_config_pagecache SIZE N
901 **
902 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
903 ** The buffer is static and is of limited size.  N might be
904 ** adjusted downward as needed to accomodate the requested size.
905 ** The revised value of N is returned.
906 **
907 ** A negative SIZE causes the buffer pointer to be NULL.
908 */
909 static int test_config_pagecache(
910   void * clientData,
911   Tcl_Interp *interp,
912   int objc,
913   Tcl_Obj *CONST objv[]
914 ){
915   int sz, N, rc;
916   Tcl_Obj *pResult;
917   static char *buf = 0;
918   if( objc!=3 ){
919     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
920     return TCL_ERROR;
921   }
922   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
923   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
924   free(buf);
925   if( sz<0 ){
926     buf = 0;
927     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
928   }else{
929     buf = malloc( (sz+4)*N );
930     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
931   }
932   pResult = Tcl_NewObj();
933   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
934   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
935   Tcl_SetObjResult(interp, pResult);
936   return TCL_OK;
937 }
938 
939 /*
940 ** Usage:    sqlite3_config_memstatus BOOLEAN
941 **
942 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
943 */
944 static int test_config_memstatus(
945   void * clientData,
946   Tcl_Interp *interp,
947   int objc,
948   Tcl_Obj *CONST objv[]
949 ){
950   int enable, rc;
951   if( objc!=2 ){
952     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
953     return TCL_ERROR;
954   }
955   if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
956   rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
957   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
958   return TCL_OK;
959 }
960 
961 /*
962 ** Usage:    sqlite3_config_chunkalloc
963 **
964 */
965 static int test_config_chunkalloc(
966   void * clientData,
967   Tcl_Interp *interp,
968   int objc,
969   Tcl_Obj *CONST objv[]
970 ){
971   int rc;
972   int nThreshold;
973   if( objc!=2 ){
974     Tcl_WrongNumArgs(interp, 1, objv, "THRESHOLD");
975     return TCL_ERROR;
976   }
977   if( Tcl_GetIntFromObj(interp, objv[1], &nThreshold) ) return TCL_ERROR;
978   rc = sqlite3_config(SQLITE_CONFIG_CHUNKALLOC, nThreshold);
979   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
980   return TCL_OK;
981 }
982 
983 /*
984 ** Usage:    sqlite3_config_lookaside  SIZE  COUNT
985 **
986 */
987 static int test_config_lookaside(
988   void * clientData,
989   Tcl_Interp *interp,
990   int objc,
991   Tcl_Obj *CONST objv[]
992 ){
993   int rc;
994   int sz, cnt;
995   if( objc!=3 ){
996     Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
997     return TCL_ERROR;
998   }
999   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1000   if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1001   rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1002   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1003   return TCL_OK;
1004 }
1005 
1006 
1007 /*
1008 ** Usage:    sqlite3_db_config_lookaside  CONNECTION  SIZE  COUNT
1009 **
1010 */
1011 static int test_db_config_lookaside(
1012   void * clientData,
1013   Tcl_Interp *interp,
1014   int objc,
1015   Tcl_Obj *CONST objv[]
1016 ){
1017   int rc;
1018   int sz, cnt;
1019   sqlite3 *db;
1020   int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1021   if( objc!=4 ){
1022     Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1023     return TCL_ERROR;
1024   }
1025   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1026   if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
1027   if( Tcl_GetIntFromObj(interp, objv[3], &cnt) ) return TCL_ERROR;
1028   rc = sqlite3_db_config(db, SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1029   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1030   return TCL_OK;
1031 }
1032 
1033 /*
1034 ** Usage:
1035 **
1036 **   sqlite3_config_heap NBYTE NMINALLOC
1037 */
1038 static int test_config_heap(
1039   void * clientData,
1040   Tcl_Interp *interp,
1041   int objc,
1042   Tcl_Obj *CONST objv[]
1043 ){
1044   static char *zBuf; /* Use this memory */
1045   static int szBuf;  /* Bytes allocated for zBuf */
1046   int nByte;         /* Size of buffer to pass to sqlite3_config() */
1047   int nMinAlloc;     /* Size of minimum allocation */
1048   int rc;            /* Return code of sqlite3_config() */
1049 
1050   Tcl_Obj * CONST *aArg = &objv[1];
1051   int nArg = objc-1;
1052 
1053   if( nArg!=2 ){
1054     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
1055     return TCL_ERROR;
1056   }
1057   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1058   if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1059 
1060   if( nByte==0 ){
1061     free( zBuf );
1062     zBuf = 0;
1063     szBuf = 0;
1064     rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
1065   }else{
1066     zBuf = realloc(zBuf, nByte);
1067     szBuf = nByte;
1068     rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
1069   }
1070 
1071   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1072   return TCL_OK;
1073 }
1074 
1075 /*
1076 ** Usage:
1077 **
1078 **   sqlite3_dump_memsys3  FILENAME
1079 **   sqlite3_dump_memsys5  FILENAME
1080 **
1081 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1082 */
1083 static int test_dump_memsys3(
1084   void * clientData,
1085   Tcl_Interp *interp,
1086   int objc,
1087   Tcl_Obj *CONST objv[]
1088 ){
1089   if( objc!=2 ){
1090     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1091     return TCL_ERROR;
1092   }
1093 
1094   switch( (int)clientData ){
1095     case 3: {
1096 #ifdef SQLITE_ENABLE_MEMSYS3
1097       extern void sqlite3Memsys3Dump(const char*);
1098       sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1099       break;
1100 #endif
1101     }
1102     case 5: {
1103 #ifdef SQLITE_ENABLE_MEMSYS5
1104       extern void sqlite3Memsys5Dump(const char*);
1105       sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1106       break;
1107 #endif
1108     }
1109   }
1110   return TCL_OK;
1111 }
1112 
1113 /*
1114 ** Usage:    sqlite3_status  OPCODE  RESETFLAG
1115 **
1116 ** Return a list of three elements which are the sqlite3_status() return
1117 ** code, the current value, and the high-water mark value.
1118 */
1119 static int test_status(
1120   void * clientData,
1121   Tcl_Interp *interp,
1122   int objc,
1123   Tcl_Obj *CONST objv[]
1124 ){
1125   int rc, iValue, mxValue;
1126   int i, op, resetFlag;
1127   const char *zOpName;
1128   static const struct {
1129     const char *zName;
1130     int op;
1131   } aOp[] = {
1132     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
1133     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
1134     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
1135     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
1136     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
1137     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
1138     { "SQLITE_STATUS_PARSER_STACK",        SQLITE_STATUS_PARSER_STACK        },
1139   };
1140   Tcl_Obj *pResult;
1141   if( objc!=3 ){
1142     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1143     return TCL_ERROR;
1144   }
1145   zOpName = Tcl_GetString(objv[1]);
1146   for(i=0; i<ArraySize(aOp); i++){
1147     if( strcmp(aOp[i].zName, zOpName)==0 ){
1148       op = aOp[i].op;
1149       break;
1150     }
1151   }
1152   if( i>=ArraySize(aOp) ){
1153     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1154   }
1155   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1156   iValue = 0;
1157   mxValue = 0;
1158   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1159   pResult = Tcl_NewObj();
1160   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1161   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1162   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1163   Tcl_SetObjResult(interp, pResult);
1164   return TCL_OK;
1165 }
1166 
1167 /*
1168 ** Usage:    sqlite3_db_status  DATABASE  OPCODE  RESETFLAG
1169 **
1170 ** Return a list of three elements which are the sqlite3_db_status() return
1171 ** code, the current value, and the high-water mark value.
1172 */
1173 static int test_db_status(
1174   void * clientData,
1175   Tcl_Interp *interp,
1176   int objc,
1177   Tcl_Obj *CONST objv[]
1178 ){
1179   int rc, iValue, mxValue;
1180   int i, op, resetFlag;
1181   const char *zOpName;
1182   sqlite3 *db;
1183   int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1184   static const struct {
1185     const char *zName;
1186     int op;
1187   } aOp[] = {
1188     { "SQLITE_DBSTATUS_LOOKASIDE_USED",    SQLITE_DBSTATUS_LOOKASIDE_USED   },
1189   };
1190   Tcl_Obj *pResult;
1191   if( objc!=4 ){
1192     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1193     return TCL_ERROR;
1194   }
1195   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1196   zOpName = Tcl_GetString(objv[2]);
1197   for(i=0; i<ArraySize(aOp); i++){
1198     if( strcmp(aOp[i].zName, zOpName)==0 ){
1199       op = aOp[i].op;
1200       break;
1201     }
1202   }
1203   if( i>=ArraySize(aOp) ){
1204     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1205   }
1206   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1207   iValue = 0;
1208   mxValue = 0;
1209   rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1210   pResult = Tcl_NewObj();
1211   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1212   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1213   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1214   Tcl_SetObjResult(interp, pResult);
1215   return TCL_OK;
1216 }
1217 
1218 /*
1219 ** install_malloc_faultsim BOOLEAN
1220 */
1221 static int test_install_malloc_faultsim(
1222   void * clientData,
1223   Tcl_Interp *interp,
1224   int objc,
1225   Tcl_Obj *CONST objv[]
1226 ){
1227   int rc;
1228   int isInstall;
1229 
1230   if( objc!=2 ){
1231     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1232     return TCL_ERROR;
1233   }
1234   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1235     return TCL_ERROR;
1236   }
1237   rc = faultsimInstall(isInstall);
1238   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1239   return TCL_OK;
1240 }
1241 
1242 /*
1243 ** Register commands with the TCL interpreter.
1244 */
1245 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1246   static struct {
1247      char *zName;
1248      Tcl_ObjCmdProc *xProc;
1249      int clientData;
1250   } aObjCmd[] = {
1251      { "sqlite3_malloc",             test_malloc                   ,0 },
1252      { "sqlite3_realloc",            test_realloc                  ,0 },
1253      { "sqlite3_free",               test_free                     ,0 },
1254      { "memset",                     test_memset                   ,0 },
1255      { "memget",                     test_memget                   ,0 },
1256      { "sqlite3_memory_used",        test_memory_used              ,0 },
1257      { "sqlite3_memory_highwater",   test_memory_highwater         ,0 },
1258      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0 },
1259      { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0 },
1260      { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0 },
1261      { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0 },
1262      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0 },
1263      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1264      { "sqlite3_memdebug_log",       test_memdebug_log             ,0 },
1265      { "sqlite3_config_scratch",     test_config_scratch           ,0 },
1266      { "sqlite3_config_pagecache",   test_config_pagecache         ,0 },
1267      { "sqlite3_status",             test_status                   ,0 },
1268      { "sqlite3_db_status",          test_db_status                ,0 },
1269      { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0 },
1270      { "sqlite3_config_heap",        test_config_heap              ,0 },
1271      { "sqlite3_config_memstatus",   test_config_memstatus         ,0 },
1272      { "sqlite3_config_chunkalloc",  test_config_chunkalloc        ,0 },
1273      { "sqlite3_config_lookaside",   test_config_lookaside         ,0 },
1274      { "sqlite3_db_config_lookaside",test_db_config_lookaside      ,0 },
1275      { "sqlite3_dump_memsys3",       test_dump_memsys3             ,3 },
1276      { "sqlite3_dump_memsys5",       test_dump_memsys3             ,5 }
1277   };
1278   int i;
1279   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1280     ClientData c = (ClientData)aObjCmd[i].clientData;
1281     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
1282   }
1283   return TCL_OK;
1284 }
1285 #endif
1286