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