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