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