xref: /sqlite-3.40.0/src/test_malloc.c (revision 067b92ba)
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 #include "sqliteInt.h"
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 #  include "sqlite_tcl.h"
19 #else
20 #  include "tcl.h"
21 #endif
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 
26 /*
27 ** This structure is used to encapsulate the global state variables used
28 ** by malloc() fault simulation.
29 */
30 static struct MemFault {
31   int iCountdown;         /* Number of pending successes before a failure */
32   int nRepeat;            /* Number of times to repeat the failure */
33   int nBenign;            /* Number of benign failures seen since last config */
34   int nFail;              /* Number of failures seen since last config */
35   int nOkBefore;          /* Successful allocations prior to the first fault */
36   int nOkAfter;           /* Successful allocations after a fault */
37   u8 enable;              /* True if enabled */
38   int isInstalled;        /* True if the fault simulation layer is installed */
39   int isBenignMode;       /* True if malloc failures are considered benign */
40   sqlite3_mem_methods m;  /* 'Real' malloc implementation */
41 } memfault;
42 
43 /*
44 ** This routine exists as a place to set a breakpoint that will
45 ** fire on any simulated malloc() failure.
46 */
47 static void sqlite3Fault(void){
48   static int cnt = 0;
49   cnt++;
50 }
51 
52 /*
53 ** This routine exists as a place to set a breakpoint that will
54 ** fire the first time any malloc() fails on a single test case.
55 ** The sqlite3Fault() routine above runs on every malloc() failure.
56 ** This routine only runs on the first such failure.
57 */
58 static void sqlite3FirstFault(void){
59   static int cnt2 = 0;
60   cnt2++;
61 }
62 
63 /*
64 ** Check to see if a fault should be simulated.  Return true to simulate
65 ** the fault.  Return false if the fault should not be simulated.
66 */
67 static int faultsimStep(void){
68   if( likely(!memfault.enable) ){
69     memfault.nOkAfter++;
70     return 0;
71   }
72   if( memfault.iCountdown>0 ){
73     memfault.iCountdown--;
74     memfault.nOkBefore++;
75     return 0;
76   }
77   if( memfault.nFail==0 ) sqlite3FirstFault();
78   sqlite3Fault();
79   memfault.nFail++;
80   if( memfault.isBenignMode>0 ){
81     memfault.nBenign++;
82   }
83   memfault.nRepeat--;
84   if( memfault.nRepeat<=0 ){
85     memfault.enable = 0;
86   }
87   return 1;
88 }
89 
90 /*
91 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
92 ** logic.
93 */
94 static void *faultsimMalloc(int n){
95   void *p = 0;
96   if( !faultsimStep() ){
97     p = memfault.m.xMalloc(n);
98   }
99   return p;
100 }
101 
102 
103 /*
104 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
105 ** logic.
106 */
107 static void *faultsimRealloc(void *pOld, int n){
108   void *p = 0;
109   if( !faultsimStep() ){
110     p = memfault.m.xRealloc(pOld, n);
111   }
112   return p;
113 }
114 
115 /*
116 ** The following method calls are passed directly through to the underlying
117 ** malloc system:
118 **
119 **     xFree
120 **     xSize
121 **     xRoundup
122 **     xInit
123 **     xShutdown
124 */
125 static void faultsimFree(void *p){
126   memfault.m.xFree(p);
127 }
128 static int faultsimSize(void *p){
129   return memfault.m.xSize(p);
130 }
131 static int faultsimRoundup(int n){
132   return memfault.m.xRoundup(n);
133 }
134 static int faultsimInit(void *p){
135   return memfault.m.xInit(memfault.m.pAppData);
136 }
137 static void faultsimShutdown(void *p){
138   memfault.m.xShutdown(memfault.m.pAppData);
139 }
140 
141 /*
142 ** This routine configures the malloc failure simulation.  After
143 ** calling this routine, the next nDelay mallocs will succeed, followed
144 ** by a block of nRepeat failures, after which malloc() calls will begin
145 ** to succeed again.
146 */
147 static void faultsimConfig(int nDelay, int nRepeat){
148   memfault.iCountdown = nDelay;
149   memfault.nRepeat = nRepeat;
150   memfault.nBenign = 0;
151   memfault.nFail = 0;
152   memfault.nOkBefore = 0;
153   memfault.nOkAfter = 0;
154   memfault.enable = nDelay>=0;
155 
156   /* Sometimes, when running multi-threaded tests, the isBenignMode
157   ** variable is not properly incremented/decremented so that it is
158   ** 0 when not inside a benign malloc block. This doesn't affect
159   ** the multi-threaded tests, as they do not use this system. But
160   ** it does affect OOM tests run later in the same process. So
161   ** zero the variable here, just to be sure.
162   */
163   memfault.isBenignMode = 0;
164 }
165 
166 /*
167 ** Return the number of faults (both hard and benign faults) that have
168 ** occurred since the injector was last configured.
169 */
170 static int faultsimFailures(void){
171   return memfault.nFail;
172 }
173 
174 /*
175 ** Return the number of benign faults that have occurred since the
176 ** injector was last configured.
177 */
178 static int faultsimBenignFailures(void){
179   return memfault.nBenign;
180 }
181 
182 /*
183 ** Return the number of successes that will occur before the next failure.
184 ** If no failures are scheduled, return -1.
185 */
186 static int faultsimPending(void){
187   if( memfault.enable ){
188     return memfault.iCountdown;
189   }else{
190     return -1;
191   }
192 }
193 
194 
195 static void faultsimBeginBenign(void){
196   memfault.isBenignMode++;
197 }
198 static void faultsimEndBenign(void){
199   memfault.isBenignMode--;
200 }
201 
202 /*
203 ** Add or remove the fault-simulation layer using sqlite3_config(). If
204 ** the argument is non-zero, the
205 */
206 static int faultsimInstall(int install){
207   static struct sqlite3_mem_methods m = {
208     faultsimMalloc,                   /* xMalloc */
209     faultsimFree,                     /* xFree */
210     faultsimRealloc,                  /* xRealloc */
211     faultsimSize,                     /* xSize */
212     faultsimRoundup,                  /* xRoundup */
213     faultsimInit,                     /* xInit */
214     faultsimShutdown,                 /* xShutdown */
215     0                                 /* pAppData */
216   };
217   int rc;
218 
219   install = (install ? 1 : 0);
220   assert(memfault.isInstalled==1 || memfault.isInstalled==0);
221 
222   if( install==memfault.isInstalled ){
223     return SQLITE_ERROR;
224   }
225 
226   if( install ){
227     rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
228     assert(memfault.m.xMalloc);
229     if( rc==SQLITE_OK ){
230       rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
231     }
232     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
233         faultsimBeginBenign, faultsimEndBenign
234     );
235   }else{
236     sqlite3_mem_methods m2;
237     assert(memfault.m.xMalloc);
238 
239     /* One should be able to reset the default memory allocator by storing
240     ** a zeroed allocator then calling GETMALLOC. */
241     memset(&m2, 0, sizeof(m2));
242     sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);
243     sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);
244     assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );
245 
246     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
247     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
248         (void*)0, (void*)0);
249   }
250 
251   if( rc==SQLITE_OK ){
252     memfault.isInstalled = 1;
253   }
254   return rc;
255 }
256 
257 #ifdef SQLITE_TEST
258 
259 /*
260 ** This function is implemented in main.c. Returns a pointer to a static
261 ** buffer containing the symbolic SQLite error code that corresponds to
262 ** the least-significant 8-bits of the integer passed as an argument.
263 ** For example:
264 **
265 **   sqlite3ErrName(1) -> "SQLITE_ERROR"
266 */
267 extern const char *sqlite3ErrName(int);
268 
269 /*
270 ** Transform pointers to text and back again
271 */
272 static void pointerToText(void *p, char *z){
273   static const char zHex[] = "0123456789abcdef";
274   int i, k;
275   unsigned int u;
276   sqlite3_uint64 n;
277   if( p==0 ){
278     strcpy(z, "0");
279     return;
280   }
281   if( sizeof(n)==sizeof(p) ){
282     memcpy(&n, &p, sizeof(p));
283   }else if( sizeof(u)==sizeof(p) ){
284     memcpy(&u, &p, sizeof(u));
285     n = u;
286   }else{
287     assert( 0 );
288   }
289   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
290     z[k] = zHex[n&0xf];
291     n >>= 4;
292   }
293   z[sizeof(p)*2] = 0;
294 }
295 static int hexToInt(int h){
296   if( h>='0' && h<='9' ){
297     return h - '0';
298   }else if( h>='a' && h<='f' ){
299     return h - 'a' + 10;
300   }else{
301     return -1;
302   }
303 }
304 static int textToPointer(const char *z, void **pp){
305   sqlite3_uint64 n = 0;
306   int i;
307   unsigned int u;
308   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
309     int v;
310     v = hexToInt(*z++);
311     if( v<0 ) return TCL_ERROR;
312     n = n*16 + v;
313   }
314   if( *z!=0 ) return TCL_ERROR;
315   if( sizeof(n)==sizeof(*pp) ){
316     memcpy(pp, &n, sizeof(n));
317   }else if( sizeof(u)==sizeof(*pp) ){
318     u = (unsigned int)n;
319     memcpy(pp, &u, sizeof(u));
320   }else{
321     assert( 0 );
322   }
323   return TCL_OK;
324 }
325 
326 /*
327 ** Usage:    sqlite3_malloc  NBYTES
328 **
329 ** Raw test interface for sqlite3_malloc().
330 */
331 static int SQLITE_TCLAPI test_malloc(
332   void * clientData,
333   Tcl_Interp *interp,
334   int objc,
335   Tcl_Obj *CONST objv[]
336 ){
337   int nByte;
338   void *p;
339   char zOut[100];
340   if( objc!=2 ){
341     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
342     return TCL_ERROR;
343   }
344   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
345   p = sqlite3_malloc((unsigned)nByte);
346   pointerToText(p, zOut);
347   Tcl_AppendResult(interp, zOut, NULL);
348   return TCL_OK;
349 }
350 
351 /*
352 ** Usage:    sqlite3_realloc  PRIOR  NBYTES
353 **
354 ** Raw test interface for sqlite3_realloc().
355 */
356 static int SQLITE_TCLAPI test_realloc(
357   void * clientData,
358   Tcl_Interp *interp,
359   int objc,
360   Tcl_Obj *CONST objv[]
361 ){
362   int nByte;
363   void *pPrior, *p;
364   char zOut[100];
365   if( objc!=3 ){
366     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
367     return TCL_ERROR;
368   }
369   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
370   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
371     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
372     return TCL_ERROR;
373   }
374   p = sqlite3_realloc(pPrior, (unsigned)nByte);
375   pointerToText(p, zOut);
376   Tcl_AppendResult(interp, zOut, NULL);
377   return TCL_OK;
378 }
379 
380 /*
381 ** Usage:    sqlite3_free  PRIOR
382 **
383 ** Raw test interface for sqlite3_free().
384 */
385 static int SQLITE_TCLAPI test_free(
386   void * clientData,
387   Tcl_Interp *interp,
388   int objc,
389   Tcl_Obj *CONST objv[]
390 ){
391   void *pPrior;
392   if( objc!=2 ){
393     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
394     return TCL_ERROR;
395   }
396   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
397     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
398     return TCL_ERROR;
399   }
400   sqlite3_free(pPrior);
401   return TCL_OK;
402 }
403 
404 /*
405 ** These routines are in test_hexio.c
406 */
407 int sqlite3TestHexToBin(const char *, int, char *);
408 int sqlite3TestBinToHex(char*,int);
409 
410 /*
411 ** Usage:    memset  ADDRESS  SIZE  HEX
412 **
413 ** Set a chunk of memory (obtained from malloc, probably) to a
414 ** specified hex pattern.
415 */
416 static int SQLITE_TCLAPI test_memset(
417   void * clientData,
418   Tcl_Interp *interp,
419   int objc,
420   Tcl_Obj *CONST objv[]
421 ){
422   void *p;
423   int size, n, i;
424   char *zHex;
425   char *zOut;
426   char zBin[100];
427 
428   if( objc!=4 ){
429     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
430     return TCL_ERROR;
431   }
432   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
433     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
434     return TCL_ERROR;
435   }
436   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
437     return TCL_ERROR;
438   }
439   if( size<=0 ){
440     Tcl_AppendResult(interp, "size must be positive", (char*)0);
441     return TCL_ERROR;
442   }
443   zHex = Tcl_GetStringFromObj(objv[3], &n);
444   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
445   n = sqlite3TestHexToBin(zHex, n, zBin);
446   if( n==0 ){
447     Tcl_AppendResult(interp, "no data", (char*)0);
448     return TCL_ERROR;
449   }
450   zOut = p;
451   for(i=0; i<size; i++){
452     zOut[i] = zBin[i%n];
453   }
454   return TCL_OK;
455 }
456 
457 /*
458 ** Usage:    memget  ADDRESS  SIZE
459 **
460 ** Return memory as hexadecimal text.
461 */
462 static int SQLITE_TCLAPI test_memget(
463   void * clientData,
464   Tcl_Interp *interp,
465   int objc,
466   Tcl_Obj *CONST objv[]
467 ){
468   void *p;
469   int size, n;
470   char *zBin;
471   char zHex[100];
472 
473   if( objc!=3 ){
474     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
475     return TCL_ERROR;
476   }
477   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
478     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
479     return TCL_ERROR;
480   }
481   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
482     return TCL_ERROR;
483   }
484   if( size<=0 ){
485     Tcl_AppendResult(interp, "size must be positive", (char*)0);
486     return TCL_ERROR;
487   }
488   zBin = p;
489   while( size>0 ){
490     if( size>(sizeof(zHex)-1)/2 ){
491       n = (sizeof(zHex)-1)/2;
492     }else{
493       n = size;
494     }
495     memcpy(zHex, zBin, n);
496     zBin += n;
497     size -= n;
498     sqlite3TestBinToHex(zHex, n);
499     Tcl_AppendResult(interp, zHex, (char*)0);
500   }
501   return TCL_OK;
502 }
503 
504 /*
505 ** Usage:    sqlite3_memory_used
506 **
507 ** Raw test interface for sqlite3_memory_used().
508 */
509 static int SQLITE_TCLAPI test_memory_used(
510   void * clientData,
511   Tcl_Interp *interp,
512   int objc,
513   Tcl_Obj *CONST objv[]
514 ){
515   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
516   return TCL_OK;
517 }
518 
519 /*
520 ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
521 **
522 ** Raw test interface for sqlite3_memory_highwater().
523 */
524 static int SQLITE_TCLAPI test_memory_highwater(
525   void * clientData,
526   Tcl_Interp *interp,
527   int objc,
528   Tcl_Obj *CONST objv[]
529 ){
530   int resetFlag = 0;
531   if( objc!=1 && objc!=2 ){
532     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
533     return TCL_ERROR;
534   }
535   if( objc==2 ){
536     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
537   }
538   Tcl_SetObjResult(interp,
539      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
540   return TCL_OK;
541 }
542 
543 /*
544 ** Usage:    sqlite3_memdebug_backtrace DEPTH
545 **
546 ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
547 ** then this routine is a no-op.
548 */
549 static int SQLITE_TCLAPI test_memdebug_backtrace(
550   void * clientData,
551   Tcl_Interp *interp,
552   int objc,
553   Tcl_Obj *CONST objv[]
554 ){
555   int depth;
556   if( objc!=2 ){
557     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
558     return TCL_ERROR;
559   }
560   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
561 #ifdef SQLITE_MEMDEBUG
562   {
563     extern void sqlite3MemdebugBacktrace(int);
564     sqlite3MemdebugBacktrace(depth);
565   }
566 #endif
567   return TCL_OK;
568 }
569 
570 /*
571 ** Usage:    sqlite3_memdebug_dump  FILENAME
572 **
573 ** Write a summary of unfreed memory to FILENAME.
574 */
575 static int SQLITE_TCLAPI test_memdebug_dump(
576   void * clientData,
577   Tcl_Interp *interp,
578   int objc,
579   Tcl_Obj *CONST objv[]
580 ){
581   if( objc!=2 ){
582     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
583     return TCL_ERROR;
584   }
585 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
586      || defined(SQLITE_POW2_MEMORY_SIZE)
587   {
588     extern void sqlite3MemdebugDump(const char*);
589     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
590   }
591 #endif
592   return TCL_OK;
593 }
594 
595 /*
596 ** Usage:    sqlite3_memdebug_malloc_count
597 **
598 ** Return the total number of times malloc() has been called.
599 */
600 static int SQLITE_TCLAPI test_memdebug_malloc_count(
601   void * clientData,
602   Tcl_Interp *interp,
603   int objc,
604   Tcl_Obj *CONST objv[]
605 ){
606   int nMalloc = -1;
607   if( objc!=1 ){
608     Tcl_WrongNumArgs(interp, 1, objv, "");
609     return TCL_ERROR;
610   }
611 #if defined(SQLITE_MEMDEBUG)
612   {
613     extern int sqlite3MemdebugMallocCount();
614     nMalloc = sqlite3MemdebugMallocCount();
615   }
616 #endif
617   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
618   return TCL_OK;
619 }
620 
621 
622 /*
623 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
624 **
625 ** where options are:
626 **
627 **     -repeat    <count>
628 **     -benigncnt <varname>
629 **
630 ** Arrange for a simulated malloc() failure after COUNTER successes.
631 ** If a repeat count is specified, the fault is repeated that many
632 ** times.
633 **
634 ** Each call to this routine overrides the prior counter value.
635 ** This routine returns the number of simulated failures that have
636 ** happened since the previous call to this routine.
637 **
638 ** To disable simulated failures, use a COUNTER of -1.
639 */
640 static int SQLITE_TCLAPI test_memdebug_fail(
641   void * clientData,
642   Tcl_Interp *interp,
643   int objc,
644   Tcl_Obj *CONST objv[]
645 ){
646   int ii;
647   int iFail;
648   int nRepeat = 1;
649   Tcl_Obj *pBenignCnt = 0;
650   int nBenign;
651   int nFail = 0;
652 
653   if( objc<2 ){
654     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
655     return TCL_ERROR;
656   }
657   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
658 
659   for(ii=2; ii<objc; ii+=2){
660     int nOption;
661     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
662     char *zErr = 0;
663 
664     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
665       if( ii==(objc-1) ){
666         zErr = "option requires an argument: ";
667       }else{
668         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
669           return TCL_ERROR;
670         }
671       }
672     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
673       if( ii==(objc-1) ){
674         zErr = "option requires an argument: ";
675       }else{
676         pBenignCnt = objv[ii+1];
677       }
678     }else{
679       zErr = "unknown option: ";
680     }
681 
682     if( zErr ){
683       Tcl_AppendResult(interp, zErr, zOption, 0);
684       return TCL_ERROR;
685     }
686   }
687 
688   nBenign = faultsimBenignFailures();
689   nFail = faultsimFailures();
690   faultsimConfig(iFail, nRepeat);
691 
692   if( pBenignCnt ){
693     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
694   }
695   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
696   return TCL_OK;
697 }
698 
699 /*
700 ** Usage:    sqlite3_memdebug_pending
701 **
702 ** Return the number of malloc() calls that will succeed before a
703 ** simulated failure occurs. A negative return value indicates that
704 ** no malloc() failure is scheduled.
705 */
706 static int SQLITE_TCLAPI test_memdebug_pending(
707   void * clientData,
708   Tcl_Interp *interp,
709   int objc,
710   Tcl_Obj *CONST objv[]
711 ){
712   int nPending;
713   if( objc!=1 ){
714     Tcl_WrongNumArgs(interp, 1, objv, "");
715     return TCL_ERROR;
716   }
717   nPending = faultsimPending();
718   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
719   return TCL_OK;
720 }
721 
722 /*
723 ** The following global variable keeps track of the number of tests
724 ** that have run.  This variable is only useful when running in the
725 ** debugger.
726 */
727 static int sqlite3_memdebug_title_count = 0;
728 
729 /*
730 ** Usage:    sqlite3_memdebug_settitle TITLE
731 **
732 ** Set a title string stored with each allocation.  The TITLE is
733 ** typically the name of the test that was running when the
734 ** allocation occurred.  The TITLE is stored with the allocation
735 ** and can be used to figure out which tests are leaking memory.
736 **
737 ** Each title overwrite the previous.
738 */
739 static int SQLITE_TCLAPI test_memdebug_settitle(
740   void * clientData,
741   Tcl_Interp *interp,
742   int objc,
743   Tcl_Obj *CONST objv[]
744 ){
745   sqlite3_memdebug_title_count++;
746   if( objc!=2 ){
747     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
748     return TCL_ERROR;
749   }
750 #ifdef SQLITE_MEMDEBUG
751   {
752     const char *zTitle;
753     extern int sqlite3MemdebugSettitle(const char*);
754     zTitle = Tcl_GetString(objv[1]);
755     sqlite3MemdebugSettitle(zTitle);
756   }
757 #endif
758   return TCL_OK;
759 }
760 
761 #define MALLOC_LOG_FRAMES  10
762 #define MALLOC_LOG_KEYINTS (                                              \
763     10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int))   \
764 )
765 static Tcl_HashTable aMallocLog;
766 static int mallocLogEnabled = 0;
767 
768 typedef struct MallocLog MallocLog;
769 struct MallocLog {
770   int nCall;
771   int nByte;
772 };
773 
774 #ifdef SQLITE_MEMDEBUG
775 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
776   if( mallocLogEnabled ){
777     MallocLog *pLog;
778     Tcl_HashEntry *pEntry;
779     int isNew;
780 
781     int aKey[MALLOC_LOG_KEYINTS];
782     unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
783 
784     memset(aKey, 0, nKey);
785     if( (sizeof(void*)*nFrame)<nKey ){
786       nKey = nFrame*sizeof(void*);
787     }
788     memcpy(aKey, aFrame, nKey);
789 
790     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
791     if( isNew ){
792       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
793       memset(pLog, 0, sizeof(MallocLog));
794       Tcl_SetHashValue(pEntry, (ClientData)pLog);
795     }else{
796       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
797     }
798 
799     pLog->nCall++;
800     pLog->nByte += nByte;
801   }
802 }
803 #endif /* SQLITE_MEMDEBUG */
804 
805 static void test_memdebug_log_clear(void){
806   Tcl_HashSearch search;
807   Tcl_HashEntry *pEntry;
808   for(
809     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
810     pEntry;
811     pEntry=Tcl_NextHashEntry(&search)
812   ){
813     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
814     Tcl_Free((char *)pLog);
815   }
816   Tcl_DeleteHashTable(&aMallocLog);
817   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
818 }
819 
820 static int SQLITE_TCLAPI test_memdebug_log(
821   void * clientData,
822   Tcl_Interp *interp,
823   int objc,
824   Tcl_Obj *CONST objv[]
825 ){
826   static int isInit = 0;
827   int iSub;
828 
829   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
830   enum MB_enum {
831       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
832   };
833 
834   if( !isInit ){
835 #ifdef SQLITE_MEMDEBUG
836     extern void sqlite3MemdebugBacktraceCallback(
837         void (*xBacktrace)(int, int, void **));
838     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
839 #endif
840     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
841     isInit = 1;
842   }
843 
844   if( objc<2 ){
845     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
846   }
847   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
848     return TCL_ERROR;
849   }
850 
851   switch( (enum MB_enum)iSub ){
852     case MB_LOG_START:
853       mallocLogEnabled = 1;
854       break;
855     case MB_LOG_STOP:
856       mallocLogEnabled = 0;
857       break;
858     case MB_LOG_DUMP: {
859       Tcl_HashSearch search;
860       Tcl_HashEntry *pEntry;
861       Tcl_Obj *pRet = Tcl_NewObj();
862 
863       assert(sizeof(Tcl_WideInt)>=sizeof(void*));
864 
865       for(
866         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
867         pEntry;
868         pEntry=Tcl_NextHashEntry(&search)
869       ){
870         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
871         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
872         Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
873         int ii;
874 
875         apElem[0] = Tcl_NewIntObj(pLog->nCall);
876         apElem[1] = Tcl_NewIntObj(pLog->nByte);
877         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
878           apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
879         }
880 
881         Tcl_ListObjAppendElement(interp, pRet,
882             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
883         );
884       }
885 
886       Tcl_SetObjResult(interp, pRet);
887       break;
888     }
889     case MB_LOG_CLEAR: {
890       test_memdebug_log_clear();
891       break;
892     }
893 
894     case MB_LOG_SYNC: {
895 #ifdef SQLITE_MEMDEBUG
896       extern void sqlite3MemdebugSync();
897       test_memdebug_log_clear();
898       mallocLogEnabled = 1;
899       sqlite3MemdebugSync();
900 #endif
901       break;
902     }
903   }
904 
905   return TCL_OK;
906 }
907 
908 /*
909 ** Usage:    sqlite3_config_pagecache SIZE N
910 **
911 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
912 ** The buffer is static and is of limited size.  N might be
913 ** adjusted downward as needed to accommodate the requested size.
914 ** The revised value of N is returned.
915 **
916 ** A negative SIZE causes the buffer pointer to be NULL.
917 */
918 static int SQLITE_TCLAPI test_config_pagecache(
919   void * clientData,
920   Tcl_Interp *interp,
921   int objc,
922   Tcl_Obj *CONST objv[]
923 ){
924   int sz, N;
925   Tcl_Obj *pRes;
926   static char *buf = 0;
927   if( objc!=3 ){
928     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
929     return TCL_ERROR;
930   }
931   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
932   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
933   free(buf);
934   buf = 0;
935 
936   /* Set the return value */
937   pRes = Tcl_NewObj();
938   Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.szPage));
939   Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.nPage));
940   Tcl_SetObjResult(interp, pRes);
941 
942   if( sz<0 ){
943     sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, 0);
944   }else{
945     buf = malloc( sz*N );
946     sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
947   }
948   return TCL_OK;
949 }
950 
951 /*
952 ** Usage:    sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
953 **
954 ** Set up the alternative test page cache.  Install if INSTALL_FLAG is
955 ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
956 ** is false.  DISCARD_CHANGE is an integer between 0 and 100 inclusive
957 ** which determines the chance of discarding a page when unpinned.  100
958 ** is certainty.  0 is never.  PRNG_SEED is the pseudo-random number generator
959 ** seed.
960 */
961 static int SQLITE_TCLAPI test_alt_pcache(
962   void * clientData,
963   Tcl_Interp *interp,
964   int objc,
965   Tcl_Obj *CONST objv[]
966 ){
967   int installFlag;
968   int discardChance = 0;
969   int prngSeed = 0;
970   int highStress = 0;
971   extern void installTestPCache(int,unsigned,unsigned,unsigned);
972   if( objc<2 || objc>5 ){
973     Tcl_WrongNumArgs(interp, 1, objv,
974         "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
975     return TCL_ERROR;
976   }
977   if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
978   if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
979      return TCL_ERROR;
980   }
981   if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
982      return TCL_ERROR;
983   }
984   if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
985     return TCL_ERROR;
986   }
987   if( discardChance<0 || discardChance>100 ){
988     Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
989                      (char*)0);
990     return TCL_ERROR;
991   }
992   installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
993                     (unsigned)highStress);
994   return TCL_OK;
995 }
996 
997 /*
998 ** Usage:    sqlite3_config_memstatus BOOLEAN
999 **
1000 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
1001 */
1002 static int SQLITE_TCLAPI test_config_memstatus(
1003   void * clientData,
1004   Tcl_Interp *interp,
1005   int objc,
1006   Tcl_Obj *CONST objv[]
1007 ){
1008   int enable, rc;
1009   if( objc!=2 ){
1010     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1011     return TCL_ERROR;
1012   }
1013   if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
1014   rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
1015   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1016   return TCL_OK;
1017 }
1018 
1019 /*
1020 ** Usage:    sqlite3_config_lookaside  SIZE  COUNT
1021 **
1022 */
1023 static int SQLITE_TCLAPI test_config_lookaside(
1024   void * clientData,
1025   Tcl_Interp *interp,
1026   int objc,
1027   Tcl_Obj *CONST objv[]
1028 ){
1029   int sz, cnt;
1030   Tcl_Obj *pRet;
1031   if( objc!=3 ){
1032     Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1033     return TCL_ERROR;
1034   }
1035   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1036   if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1037   pRet = Tcl_NewObj();
1038   Tcl_ListObjAppendElement(
1039       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1040   );
1041   Tcl_ListObjAppendElement(
1042       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1043   );
1044   sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1045   Tcl_SetObjResult(interp, pRet);
1046   return TCL_OK;
1047 }
1048 
1049 
1050 /*
1051 ** Usage:    sqlite3_db_config_lookaside  CONNECTION  BUFID  SIZE  COUNT
1052 **
1053 ** There are two static buffers with BUFID 1 and 2.   Each static buffer
1054 ** is 10KB in size.  A BUFID of 0 indicates that the buffer should be NULL
1055 ** which will cause sqlite3_db_config() to allocate space on its own.
1056 */
1057 static int SQLITE_TCLAPI test_db_config_lookaside(
1058   void * clientData,
1059   Tcl_Interp *interp,
1060   int objc,
1061   Tcl_Obj *CONST objv[]
1062 ){
1063   int rc;
1064   int sz, cnt;
1065   sqlite3 *db;
1066   int bufid;
1067   static char azBuf[2][10000];
1068   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1069   if( objc!=5 ){
1070     Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1071     return TCL_ERROR;
1072   }
1073   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1074   if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1075   if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1076   if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1077   if( bufid==0 ){
1078     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);
1079   }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1080     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1081   }else{
1082     Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1083     return TCL_ERROR;
1084   }
1085   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1086   return TCL_OK;
1087 }
1088 
1089 /*
1090 ** Usage:    sqlite3_config_heap NBYTE NMINALLOC
1091 */
1092 static int SQLITE_TCLAPI test_config_heap(
1093   void * clientData,
1094   Tcl_Interp *interp,
1095   int objc,
1096   Tcl_Obj *CONST objv[]
1097 ){
1098   static char *zBuf; /* Use this memory */
1099   int nByte;         /* Size of buffer to pass to sqlite3_config() */
1100   int nMinAlloc;     /* Size of minimum allocation */
1101   int rc;            /* Return code of sqlite3_config() */
1102 
1103   Tcl_Obj * CONST *aArg = &objv[1];
1104   int nArg = objc-1;
1105 
1106   if( nArg!=2 ){
1107     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
1108     return TCL_ERROR;
1109   }
1110   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1111   if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1112 
1113   if( nByte==0 ){
1114     free( zBuf );
1115     zBuf = 0;
1116     rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
1117   }else{
1118     zBuf = realloc(zBuf, nByte);
1119     rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
1120   }
1121 
1122   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1123   return TCL_OK;
1124 }
1125 
1126 /*
1127 ** Usage:    sqlite3_config_heap_size NBYTE
1128 */
1129 static int SQLITE_TCLAPI test_config_heap_size(
1130   void * clientData,
1131   Tcl_Interp *interp,
1132   int objc,
1133   Tcl_Obj *CONST objv[]
1134 ){
1135   int nByte;         /* Size to pass to sqlite3_config() */
1136   int rc;            /* Return code of sqlite3_config() */
1137 
1138   Tcl_Obj * CONST *aArg = &objv[1];
1139   int nArg = objc-1;
1140 
1141   if( nArg!=1 ){
1142     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
1143     return TCL_ERROR;
1144   }
1145   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1146 
1147   rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
1148 
1149   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1150   return TCL_OK;
1151 }
1152 
1153 /*
1154 ** Usage:    sqlite3_config_error  [DB]
1155 **
1156 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1157 ** opcodes and verify that they return errors.
1158 */
1159 static int SQLITE_TCLAPI test_config_error(
1160   void * clientData,
1161   Tcl_Interp *interp,
1162   int objc,
1163   Tcl_Obj *CONST objv[]
1164 ){
1165   sqlite3 *db;
1166   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1167 
1168   if( objc!=2 && objc!=1 ){
1169     Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1170     return TCL_ERROR;
1171   }
1172   if( objc==2 ){
1173     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1174     if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1175       Tcl_AppendResult(interp,
1176             "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1177             (char*)0);
1178       return TCL_ERROR;
1179     }
1180   }else{
1181     if( sqlite3_config(99999)!=SQLITE_ERROR ){
1182       Tcl_AppendResult(interp,
1183           "sqlite3_config(99999) does not return SQLITE_ERROR",
1184           (char*)0);
1185       return TCL_ERROR;
1186     }
1187   }
1188   return TCL_OK;
1189 }
1190 
1191 /*
1192 ** Usage:    sqlite3_config_uri  BOOLEAN
1193 **
1194 ** Enables or disables interpretation of URI parameters by default using
1195 ** SQLITE_CONFIG_URI.
1196 */
1197 static int SQLITE_TCLAPI test_config_uri(
1198   void * clientData,
1199   Tcl_Interp *interp,
1200   int objc,
1201   Tcl_Obj *CONST objv[]
1202 ){
1203   int rc;
1204   int bOpenUri;
1205 
1206   if( objc!=2 ){
1207     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1208     return TCL_ERROR;
1209   }
1210   if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
1211     return TCL_ERROR;
1212   }
1213 
1214   rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
1215   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1216 
1217   return TCL_OK;
1218 }
1219 
1220 /*
1221 ** Usage:    sqlite3_config_cis  BOOLEAN
1222 **
1223 ** Enables or disables the use of the covering-index scan optimization.
1224 ** SQLITE_CONFIG_COVERING_INDEX_SCAN.
1225 */
1226 static int SQLITE_TCLAPI test_config_cis(
1227   void * clientData,
1228   Tcl_Interp *interp,
1229   int objc,
1230   Tcl_Obj *CONST objv[]
1231 ){
1232   int rc;
1233   int bUseCis;
1234 
1235   if( objc!=2 ){
1236     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1237     return TCL_ERROR;
1238   }
1239   if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){
1240     return TCL_ERROR;
1241   }
1242 
1243   rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);
1244   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1245 
1246   return TCL_OK;
1247 }
1248 
1249 /*
1250 ** Usage:    sqlite3_config_pmasz  INTEGER
1251 **
1252 ** Set the minimum PMA size.
1253 */
1254 static int SQLITE_TCLAPI test_config_pmasz(
1255   void * clientData,
1256   Tcl_Interp *interp,
1257   int objc,
1258   Tcl_Obj *CONST objv[]
1259 ){
1260   int rc;
1261   int iPmaSz;
1262 
1263   if( objc!=2 ){
1264     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1265     return TCL_ERROR;
1266   }
1267   if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){
1268     return TCL_ERROR;
1269   }
1270 
1271   rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz);
1272   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1273 
1274   return TCL_OK;
1275 }
1276 
1277 
1278 /*
1279 ** Usage:    sqlite3_dump_memsys3  FILENAME
1280 **           sqlite3_dump_memsys5  FILENAME
1281 **
1282 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1283 */
1284 static int SQLITE_TCLAPI test_dump_memsys3(
1285   void * clientData,
1286   Tcl_Interp *interp,
1287   int objc,
1288   Tcl_Obj *CONST objv[]
1289 ){
1290   if( objc!=2 ){
1291     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1292     return TCL_ERROR;
1293   }
1294 
1295   switch( SQLITE_PTR_TO_INT(clientData) ){
1296     case 3: {
1297 #ifdef SQLITE_ENABLE_MEMSYS3
1298       extern void sqlite3Memsys3Dump(const char*);
1299       sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1300       break;
1301 #endif
1302     }
1303     case 5: {
1304 #ifdef SQLITE_ENABLE_MEMSYS5
1305       extern void sqlite3Memsys5Dump(const char*);
1306       sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1307       break;
1308 #endif
1309     }
1310   }
1311   return TCL_OK;
1312 }
1313 
1314 /*
1315 ** Usage:    sqlite3_status  OPCODE  RESETFLAG
1316 **
1317 ** Return a list of three elements which are the sqlite3_status() return
1318 ** code, the current value, and the high-water mark value.
1319 */
1320 static int SQLITE_TCLAPI test_status(
1321   void * clientData,
1322   Tcl_Interp *interp,
1323   int objc,
1324   Tcl_Obj *CONST objv[]
1325 ){
1326   int rc, iValue, mxValue;
1327   int i, op = 0, resetFlag;
1328   const char *zOpName;
1329   static const struct {
1330     const char *zName;
1331     int op;
1332   } aOp[] = {
1333     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
1334     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
1335     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
1336     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
1337     { "SQLITE_STATUS_PAGECACHE_SIZE",      SQLITE_STATUS_PAGECACHE_SIZE      },
1338     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
1339     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
1340     { "SQLITE_STATUS_SCRATCH_SIZE",        SQLITE_STATUS_SCRATCH_SIZE        },
1341     { "SQLITE_STATUS_PARSER_STACK",        SQLITE_STATUS_PARSER_STACK        },
1342     { "SQLITE_STATUS_MALLOC_COUNT",        SQLITE_STATUS_MALLOC_COUNT        },
1343   };
1344   Tcl_Obj *pResult;
1345   if( objc!=3 ){
1346     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1347     return TCL_ERROR;
1348   }
1349   zOpName = Tcl_GetString(objv[1]);
1350   for(i=0; i<ArraySize(aOp); i++){
1351     if( strcmp(aOp[i].zName, zOpName)==0 ){
1352       op = aOp[i].op;
1353       break;
1354     }
1355   }
1356   if( i>=ArraySize(aOp) ){
1357     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1358   }
1359   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1360   iValue = 0;
1361   mxValue = 0;
1362   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1363   pResult = Tcl_NewObj();
1364   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1365   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1366   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1367   Tcl_SetObjResult(interp, pResult);
1368   return TCL_OK;
1369 }
1370 
1371 /*
1372 ** Usage:    sqlite3_db_status  DATABASE  OPCODE  RESETFLAG
1373 **
1374 ** Return a list of three elements which are the sqlite3_db_status() return
1375 ** code, the current value, and the high-water mark value.
1376 */
1377 static int SQLITE_TCLAPI test_db_status(
1378   void * clientData,
1379   Tcl_Interp *interp,
1380   int objc,
1381   Tcl_Obj *CONST objv[]
1382 ){
1383   int rc, iValue, mxValue;
1384   int i, op = 0, resetFlag;
1385   const char *zOpName;
1386   sqlite3 *db;
1387   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1388   static const struct {
1389     const char *zName;
1390     int op;
1391   } aOp[] = {
1392     { "LOOKASIDE_USED",      SQLITE_DBSTATUS_LOOKASIDE_USED      },
1393     { "CACHE_USED",          SQLITE_DBSTATUS_CACHE_USED          },
1394     { "SCHEMA_USED",         SQLITE_DBSTATUS_SCHEMA_USED         },
1395     { "STMT_USED",           SQLITE_DBSTATUS_STMT_USED           },
1396     { "LOOKASIDE_HIT",       SQLITE_DBSTATUS_LOOKASIDE_HIT       },
1397     { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
1398     { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
1399     { "CACHE_HIT",           SQLITE_DBSTATUS_CACHE_HIT           },
1400     { "CACHE_MISS",          SQLITE_DBSTATUS_CACHE_MISS          },
1401     { "CACHE_WRITE",         SQLITE_DBSTATUS_CACHE_WRITE         },
1402     { "DEFERRED_FKS",        SQLITE_DBSTATUS_DEFERRED_FKS        },
1403     { "CACHE_USED_SHARED",   SQLITE_DBSTATUS_CACHE_USED_SHARED   },
1404     { "CACHE_SPILL",         SQLITE_DBSTATUS_CACHE_SPILL         },
1405   };
1406   Tcl_Obj *pResult;
1407   if( objc!=4 ){
1408     Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");
1409     return TCL_ERROR;
1410   }
1411   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1412   zOpName = Tcl_GetString(objv[2]);
1413   if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
1414   if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
1415   for(i=0; i<ArraySize(aOp); i++){
1416     if( strcmp(aOp[i].zName, zOpName)==0 ){
1417       op = aOp[i].op;
1418       break;
1419     }
1420   }
1421   if( i>=ArraySize(aOp) ){
1422     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1423   }
1424   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1425   iValue = 0;
1426   mxValue = 0;
1427   rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1428   pResult = Tcl_NewObj();
1429   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1430   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1431   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1432   Tcl_SetObjResult(interp, pResult);
1433   return TCL_OK;
1434 }
1435 
1436 /*
1437 ** install_malloc_faultsim BOOLEAN
1438 */
1439 static int SQLITE_TCLAPI test_install_malloc_faultsim(
1440   void * clientData,
1441   Tcl_Interp *interp,
1442   int objc,
1443   Tcl_Obj *CONST objv[]
1444 ){
1445   int rc;
1446   int isInstall;
1447 
1448   if( objc!=2 ){
1449     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1450     return TCL_ERROR;
1451   }
1452   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1453     return TCL_ERROR;
1454   }
1455   rc = faultsimInstall(isInstall);
1456   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1457   return TCL_OK;
1458 }
1459 
1460 /*
1461 ** sqlite3_install_memsys3
1462 */
1463 static int SQLITE_TCLAPI test_install_memsys3(
1464   void * clientData,
1465   Tcl_Interp *interp,
1466   int objc,
1467   Tcl_Obj *CONST objv[]
1468 ){
1469   int rc = SQLITE_MISUSE;
1470 #ifdef SQLITE_ENABLE_MEMSYS3
1471   const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
1472   rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
1473 #endif
1474   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
1475   return TCL_OK;
1476 }
1477 
1478 static int SQLITE_TCLAPI test_vfs_oom_test(
1479   void * clientData,
1480   Tcl_Interp *interp,
1481   int objc,
1482   Tcl_Obj *CONST objv[]
1483 ){
1484   extern int sqlite3_memdebug_vfs_oom_test;
1485   if( objc>2 ){
1486     Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
1487     return TCL_ERROR;
1488   }else if( objc==2 ){
1489     int iNew;
1490     if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
1491     sqlite3_memdebug_vfs_oom_test = iNew;
1492   }
1493   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
1494   return TCL_OK;
1495 }
1496 
1497 /*
1498 ** Register commands with the TCL interpreter.
1499 */
1500 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1501   static struct {
1502      char *zName;
1503      Tcl_ObjCmdProc *xProc;
1504      int clientData;
1505   } aObjCmd[] = {
1506      { "sqlite3_malloc",             test_malloc                   ,0 },
1507      { "sqlite3_realloc",            test_realloc                  ,0 },
1508      { "sqlite3_free",               test_free                     ,0 },
1509      { "memset",                     test_memset                   ,0 },
1510      { "memget",                     test_memget                   ,0 },
1511      { "sqlite3_memory_used",        test_memory_used              ,0 },
1512      { "sqlite3_memory_highwater",   test_memory_highwater         ,0 },
1513      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0 },
1514      { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0 },
1515      { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0 },
1516      { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0 },
1517      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0 },
1518      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1519      { "sqlite3_memdebug_log",       test_memdebug_log             ,0 },
1520      { "sqlite3_config_pagecache",   test_config_pagecache         ,0 },
1521      { "sqlite3_config_alt_pcache",  test_alt_pcache               ,0 },
1522      { "sqlite3_status",             test_status                   ,0 },
1523      { "sqlite3_db_status",          test_db_status                ,0 },
1524      { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0 },
1525      { "sqlite3_config_heap",        test_config_heap              ,0 },
1526      { "sqlite3_config_heap_size",   test_config_heap_size         ,0 },
1527      { "sqlite3_config_memstatus",   test_config_memstatus         ,0 },
1528      { "sqlite3_config_lookaside",   test_config_lookaside         ,0 },
1529      { "sqlite3_config_error",       test_config_error             ,0 },
1530      { "sqlite3_config_uri",         test_config_uri               ,0 },
1531      { "sqlite3_config_cis",         test_config_cis               ,0 },
1532      { "sqlite3_config_pmasz",       test_config_pmasz             ,0 },
1533      { "sqlite3_db_config_lookaside",test_db_config_lookaside      ,0 },
1534      { "sqlite3_dump_memsys3",       test_dump_memsys3             ,3 },
1535      { "sqlite3_dump_memsys5",       test_dump_memsys3             ,5 },
1536      { "sqlite3_install_memsys3",    test_install_memsys3          ,0 },
1537      { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test          ,0 },
1538   };
1539   int i;
1540   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1541     ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
1542     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
1543   }
1544   return TCL_OK;
1545 }
1546 #endif
1547