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