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