xref: /sqlite-3.40.0/src/test_malloc.c (revision b232c232)
12f999a67Sdrh /*
22f999a67Sdrh ** 2007 August 15
32f999a67Sdrh **
42f999a67Sdrh ** The author disclaims copyright to this source code.  In place of
52f999a67Sdrh ** a legal notice, here is a blessing:
62f999a67Sdrh **
72f999a67Sdrh **    May you do good and not evil.
82f999a67Sdrh **    May you find forgiveness for yourself and forgive others.
92f999a67Sdrh **    May you share freely, never taking more than you give.
102f999a67Sdrh **
112f999a67Sdrh *************************************************************************
122f999a67Sdrh **
132f999a67Sdrh ** This file contains code used to implement test interfaces to the
142f999a67Sdrh ** memory allocation subsystem.
152f999a67Sdrh **
16*b232c232Sdrh ** $Id: test_malloc.c,v 1.51 2008/11/19 01:20:26 drh Exp $
172f999a67Sdrh */
182f999a67Sdrh #include "sqliteInt.h"
192f999a67Sdrh #include "tcl.h"
202f999a67Sdrh #include <stdlib.h>
212f999a67Sdrh #include <string.h>
222f999a67Sdrh #include <assert.h>
232f999a67Sdrh 
24ef05f2dfSdanielk1977 /*
25ef05f2dfSdanielk1977 ** This structure is used to encapsulate the global state variables used
26ef05f2dfSdanielk1977 ** by malloc() fault simulation.
27ef05f2dfSdanielk1977 */
28ef05f2dfSdanielk1977 static struct MemFault {
29ef05f2dfSdanielk1977   int iCountdown;         /* Number of pending successes before a failure */
30ef05f2dfSdanielk1977   int nRepeat;            /* Number of times to repeat the failure */
31ef05f2dfSdanielk1977   int nBenign;            /* Number of benign failures seen since last config */
32ef05f2dfSdanielk1977   int nFail;              /* Number of failures seen since last config */
33ef05f2dfSdanielk1977   u8 enable;              /* True if enabled */
34ef05f2dfSdanielk1977   int isInstalled;        /* True if the fault simulation layer is installed */
352d1d86fbSdanielk1977   int isBenignMode;       /* True if malloc failures are considered benign */
36ef05f2dfSdanielk1977   sqlite3_mem_methods m;  /* 'Real' malloc implementation */
37ef05f2dfSdanielk1977 } memfault;
38ef05f2dfSdanielk1977 
39ef05f2dfSdanielk1977 /*
40ef05f2dfSdanielk1977 ** This routine exists as a place to set a breakpoint that will
41ef05f2dfSdanielk1977 ** fire on any simulated malloc() failure.
42ef05f2dfSdanielk1977 */
43ef05f2dfSdanielk1977 static void sqlite3Fault(void){
44ef05f2dfSdanielk1977   static int cnt = 0;
45ef05f2dfSdanielk1977   cnt++;
46ef05f2dfSdanielk1977 }
47ef05f2dfSdanielk1977 
48ef05f2dfSdanielk1977 /*
49ef05f2dfSdanielk1977 ** Check to see if a fault should be simulated.  Return true to simulate
50ef05f2dfSdanielk1977 ** the fault.  Return false if the fault should not be simulated.
51ef05f2dfSdanielk1977 */
52ef05f2dfSdanielk1977 static int faultsimStep(){
53ef05f2dfSdanielk1977   if( likely(!memfault.enable) ){
54ef05f2dfSdanielk1977     return 0;
55ef05f2dfSdanielk1977   }
56ef05f2dfSdanielk1977   if( memfault.iCountdown>0 ){
57ef05f2dfSdanielk1977     memfault.iCountdown--;
58ef05f2dfSdanielk1977     return 0;
59ef05f2dfSdanielk1977   }
60ef05f2dfSdanielk1977   sqlite3Fault();
61ef05f2dfSdanielk1977   memfault.nFail++;
622d1d86fbSdanielk1977   if( memfault.isBenignMode>0 ){
63ef05f2dfSdanielk1977     memfault.nBenign++;
64ef05f2dfSdanielk1977   }
65ef05f2dfSdanielk1977   memfault.nRepeat--;
66ef05f2dfSdanielk1977   if( memfault.nRepeat<=0 ){
67ef05f2dfSdanielk1977     memfault.enable = 0;
68ef05f2dfSdanielk1977   }
69ef05f2dfSdanielk1977   return 1;
70ef05f2dfSdanielk1977 }
71ef05f2dfSdanielk1977 
72ef05f2dfSdanielk1977 /*
73ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
74ef05f2dfSdanielk1977 ** logic.
75ef05f2dfSdanielk1977 */
76ef05f2dfSdanielk1977 static void *faultsimMalloc(int n){
77ef05f2dfSdanielk1977   void *p = 0;
78ef05f2dfSdanielk1977   if( !faultsimStep() ){
79ef05f2dfSdanielk1977     p = memfault.m.xMalloc(n);
80ef05f2dfSdanielk1977   }
81ef05f2dfSdanielk1977   return p;
82ef05f2dfSdanielk1977 }
83ef05f2dfSdanielk1977 
84ef05f2dfSdanielk1977 
85ef05f2dfSdanielk1977 /*
86ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
87ef05f2dfSdanielk1977 ** logic.
88ef05f2dfSdanielk1977 */
89ef05f2dfSdanielk1977 static void *faultsimRealloc(void *pOld, int n){
90ef05f2dfSdanielk1977   void *p = 0;
91ef05f2dfSdanielk1977   if( !faultsimStep() ){
92ef05f2dfSdanielk1977     p = memfault.m.xRealloc(pOld, n);
93ef05f2dfSdanielk1977   }
94ef05f2dfSdanielk1977   return p;
95ef05f2dfSdanielk1977 }
96ef05f2dfSdanielk1977 
97ef05f2dfSdanielk1977 /*
98ef05f2dfSdanielk1977 ** The following method calls are passed directly through to the underlying
99ef05f2dfSdanielk1977 ** malloc system:
100ef05f2dfSdanielk1977 **
101ef05f2dfSdanielk1977 **     xFree
102ef05f2dfSdanielk1977 **     xSize
103ef05f2dfSdanielk1977 **     xRoundup
104ef05f2dfSdanielk1977 **     xInit
105ef05f2dfSdanielk1977 **     xShutdown
106ef05f2dfSdanielk1977 */
107ef05f2dfSdanielk1977 static void faultsimFree(void *p){
108ef05f2dfSdanielk1977   memfault.m.xFree(p);
109ef05f2dfSdanielk1977 }
110ef05f2dfSdanielk1977 static int faultsimSize(void *p){
111ef05f2dfSdanielk1977   return memfault.m.xSize(p);
112ef05f2dfSdanielk1977 }
113ef05f2dfSdanielk1977 static int faultsimRoundup(int n){
114ef05f2dfSdanielk1977   return memfault.m.xRoundup(n);
115ef05f2dfSdanielk1977 }
116ef05f2dfSdanielk1977 static int faultsimInit(void *p){
117ef05f2dfSdanielk1977   return memfault.m.xInit(memfault.m.pAppData);
118ef05f2dfSdanielk1977 }
119ef05f2dfSdanielk1977 static void faultsimShutdown(void *p){
120ef05f2dfSdanielk1977   memfault.m.xShutdown(memfault.m.pAppData);
121ef05f2dfSdanielk1977 }
122ef05f2dfSdanielk1977 
123ef05f2dfSdanielk1977 /*
124ef05f2dfSdanielk1977 ** This routine configures the malloc failure simulation.  After
125ef05f2dfSdanielk1977 ** calling this routine, the next nDelay mallocs will succeed, followed
126ef05f2dfSdanielk1977 ** by a block of nRepeat failures, after which malloc() calls will begin
127ef05f2dfSdanielk1977 ** to succeed again.
128ef05f2dfSdanielk1977 */
129ef05f2dfSdanielk1977 static void faultsimConfig(int nDelay, int nRepeat){
130ef05f2dfSdanielk1977   memfault.iCountdown = nDelay;
131ef05f2dfSdanielk1977   memfault.nRepeat = nRepeat;
132ef05f2dfSdanielk1977   memfault.nBenign = 0;
133ef05f2dfSdanielk1977   memfault.nFail = 0;
134ef05f2dfSdanielk1977   memfault.enable = nDelay>=0;
135ef05f2dfSdanielk1977 }
136ef05f2dfSdanielk1977 
137ef05f2dfSdanielk1977 /*
138ef05f2dfSdanielk1977 ** Return the number of faults (both hard and benign faults) that have
139ef05f2dfSdanielk1977 ** occurred since the injector was last configured.
140ef05f2dfSdanielk1977 */
141ef05f2dfSdanielk1977 static int faultsimFailures(void){
142ef05f2dfSdanielk1977   return memfault.nFail;
143ef05f2dfSdanielk1977 }
144ef05f2dfSdanielk1977 
145ef05f2dfSdanielk1977 /*
146ef05f2dfSdanielk1977 ** Return the number of benign faults that have occurred since the
147ef05f2dfSdanielk1977 ** injector was last configured.
148ef05f2dfSdanielk1977 */
149ef05f2dfSdanielk1977 static int faultsimBenignFailures(void){
150ef05f2dfSdanielk1977   return memfault.nBenign;
151ef05f2dfSdanielk1977 }
152ef05f2dfSdanielk1977 
153ef05f2dfSdanielk1977 /*
154ef05f2dfSdanielk1977 ** Return the number of successes that will occur before the next failure.
155ef05f2dfSdanielk1977 ** If no failures are scheduled, return -1.
156ef05f2dfSdanielk1977 */
157ef05f2dfSdanielk1977 static int faultsimPending(void){
158ef05f2dfSdanielk1977   if( memfault.enable ){
159ef05f2dfSdanielk1977     return memfault.iCountdown;
160ef05f2dfSdanielk1977   }else{
161ef05f2dfSdanielk1977     return -1;
162ef05f2dfSdanielk1977   }
163ef05f2dfSdanielk1977 }
164ef05f2dfSdanielk1977 
1652d1d86fbSdanielk1977 
1662d1d86fbSdanielk1977 static void faultsimBeginBenign(void){
1672d1d86fbSdanielk1977   memfault.isBenignMode++;
1682d1d86fbSdanielk1977 }
1692d1d86fbSdanielk1977 static void faultsimEndBenign(void){
1702d1d86fbSdanielk1977   memfault.isBenignMode--;
1712d1d86fbSdanielk1977 }
1722d1d86fbSdanielk1977 
173ef05f2dfSdanielk1977 /*
174ef05f2dfSdanielk1977 ** Add or remove the fault-simulation layer using sqlite3_config(). If
175ef05f2dfSdanielk1977 ** the argument is non-zero, the
176ef05f2dfSdanielk1977 */
177ef05f2dfSdanielk1977 static int faultsimInstall(int install){
178ef05f2dfSdanielk1977   static struct sqlite3_mem_methods m = {
179ef05f2dfSdanielk1977     faultsimMalloc,                   /* xMalloc */
180ef05f2dfSdanielk1977     faultsimFree,                     /* xFree */
181ef05f2dfSdanielk1977     faultsimRealloc,                  /* xRealloc */
182ef05f2dfSdanielk1977     faultsimSize,                     /* xSize */
183ef05f2dfSdanielk1977     faultsimRoundup,                  /* xRoundup */
184ef05f2dfSdanielk1977     faultsimInit,                     /* xInit */
185ef05f2dfSdanielk1977     faultsimShutdown,                 /* xShutdown */
186ef05f2dfSdanielk1977     0                                 /* pAppData */
187ef05f2dfSdanielk1977   };
188ef05f2dfSdanielk1977   int rc;
189ef05f2dfSdanielk1977 
190ef05f2dfSdanielk1977   install = (install ? 1 : 0);
191ef05f2dfSdanielk1977   assert(memfault.isInstalled==1 || memfault.isInstalled==0);
192ef05f2dfSdanielk1977 
193ef05f2dfSdanielk1977   if( install==memfault.isInstalled ){
194ef05f2dfSdanielk1977     return SQLITE_ERROR;
195ef05f2dfSdanielk1977   }
196ef05f2dfSdanielk1977 
1972d1d86fbSdanielk1977   if( install ){
198ef05f2dfSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
199ef05f2dfSdanielk1977     assert(memfault.m.xMalloc);
200ef05f2dfSdanielk1977     if( rc==SQLITE_OK ){
201ef05f2dfSdanielk1977       rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
202ef05f2dfSdanielk1977     }
2032d1d86fbSdanielk1977     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
2042d1d86fbSdanielk1977         faultsimBeginBenign, faultsimEndBenign
2052d1d86fbSdanielk1977     );
2062d1d86fbSdanielk1977   }else{
2071b67f3caSdrh     sqlite3_mem_methods m;
2082d1d86fbSdanielk1977     assert(memfault.m.xMalloc);
2091b67f3caSdrh 
2101b67f3caSdrh     /* One should be able to reset the default memory allocator by storing
2111b67f3caSdrh     ** a zeroed allocator then calling GETMALLOC. */
2121b67f3caSdrh     memset(&m, 0, sizeof(m));
2131b67f3caSdrh     sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
2141b67f3caSdrh     sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
2151b67f3caSdrh     assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
2161b67f3caSdrh 
2172d1d86fbSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
2182d1d86fbSdanielk1977     sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
2192d1d86fbSdanielk1977   }
220ef05f2dfSdanielk1977 
221ef05f2dfSdanielk1977   if( rc==SQLITE_OK ){
222ef05f2dfSdanielk1977     memfault.isInstalled = 1;
223ef05f2dfSdanielk1977   }
224ef05f2dfSdanielk1977   return rc;
225ef05f2dfSdanielk1977 }
226ef05f2dfSdanielk1977 
227ef05f2dfSdanielk1977 #ifdef SQLITE_TEST
228ef05f2dfSdanielk1977 
229ef05f2dfSdanielk1977 /*
230ef05f2dfSdanielk1977 ** This function is implemented in test1.c. Returns a pointer to a static
231ef05f2dfSdanielk1977 ** buffer containing the symbolic SQLite error code that corresponds to
232ef05f2dfSdanielk1977 ** the least-significant 8-bits of the integer passed as an argument.
233ef05f2dfSdanielk1977 ** For example:
234ef05f2dfSdanielk1977 **
235ef05f2dfSdanielk1977 **   sqlite3TestErrorName(1) -> "SQLITE_ERROR"
236ef05f2dfSdanielk1977 */
237d09414cdSdanielk1977 const char *sqlite3TestErrorName(int);
238d09414cdSdanielk1977 
2392f999a67Sdrh /*
2402f999a67Sdrh ** Transform pointers to text and back again
2412f999a67Sdrh */
2422f999a67Sdrh static void pointerToText(void *p, char *z){
2432f999a67Sdrh   static const char zHex[] = "0123456789abcdef";
2442f999a67Sdrh   int i, k;
2454a50aac5Sdrh   unsigned int u;
2464a50aac5Sdrh   sqlite3_uint64 n;
2478a42cbd3Sdrh   if( p==0 ){
2488a42cbd3Sdrh     strcpy(z, "0");
2498a42cbd3Sdrh     return;
2508a42cbd3Sdrh   }
2514a50aac5Sdrh   if( sizeof(n)==sizeof(p) ){
2524a50aac5Sdrh     memcpy(&n, &p, sizeof(p));
2534a50aac5Sdrh   }else if( sizeof(u)==sizeof(p) ){
2544a50aac5Sdrh     memcpy(&u, &p, sizeof(u));
2554a50aac5Sdrh     n = u;
2564a50aac5Sdrh   }else{
2574a50aac5Sdrh     assert( 0 );
2584a50aac5Sdrh   }
2592f999a67Sdrh   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
2602f999a67Sdrh     z[k] = zHex[n&0xf];
2612f999a67Sdrh     n >>= 4;
2622f999a67Sdrh   }
2632f999a67Sdrh   z[sizeof(p)*2] = 0;
2642f999a67Sdrh }
2652f999a67Sdrh static int hexToInt(int h){
2662f999a67Sdrh   if( h>='0' && h<='9' ){
2672f999a67Sdrh     return h - '0';
2682f999a67Sdrh   }else if( h>='a' && h<='f' ){
2692f999a67Sdrh     return h - 'a' + 10;
2702f999a67Sdrh   }else{
2712f999a67Sdrh     return -1;
2722f999a67Sdrh   }
2732f999a67Sdrh }
2742f999a67Sdrh static int textToPointer(const char *z, void **pp){
2752f999a67Sdrh   sqlite3_uint64 n = 0;
2762f999a67Sdrh   int i;
2774a50aac5Sdrh   unsigned int u;
2782f999a67Sdrh   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
2792f999a67Sdrh     int v;
2802f999a67Sdrh     v = hexToInt(*z++);
2812f999a67Sdrh     if( v<0 ) return TCL_ERROR;
2822f999a67Sdrh     n = n*16 + v;
2832f999a67Sdrh   }
2842f999a67Sdrh   if( *z!=0 ) return TCL_ERROR;
2854a50aac5Sdrh   if( sizeof(n)==sizeof(*pp) ){
2864a50aac5Sdrh     memcpy(pp, &n, sizeof(n));
2874a50aac5Sdrh   }else if( sizeof(u)==sizeof(*pp) ){
2884a50aac5Sdrh     u = (unsigned int)n;
2894a50aac5Sdrh     memcpy(pp, &u, sizeof(u));
2904a50aac5Sdrh   }else{
2914a50aac5Sdrh     assert( 0 );
2924a50aac5Sdrh   }
2932f999a67Sdrh   return TCL_OK;
2942f999a67Sdrh }
2952f999a67Sdrh 
2962f999a67Sdrh /*
2972f999a67Sdrh ** Usage:    sqlite3_malloc  NBYTES
2982f999a67Sdrh **
2992f999a67Sdrh ** Raw test interface for sqlite3_malloc().
3002f999a67Sdrh */
3012f999a67Sdrh static int test_malloc(
3022f999a67Sdrh   void * clientData,
3032f999a67Sdrh   Tcl_Interp *interp,
3042f999a67Sdrh   int objc,
3052f999a67Sdrh   Tcl_Obj *CONST objv[]
3062f999a67Sdrh ){
3072f999a67Sdrh   int nByte;
3082f999a67Sdrh   void *p;
3092f999a67Sdrh   char zOut[100];
3102f999a67Sdrh   if( objc!=2 ){
3112f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
3122f999a67Sdrh     return TCL_ERROR;
3132f999a67Sdrh   }
3142f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
3152f999a67Sdrh   p = sqlite3_malloc((unsigned)nByte);
3162f999a67Sdrh   pointerToText(p, zOut);
3172f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
3182f999a67Sdrh   return TCL_OK;
3192f999a67Sdrh }
3202f999a67Sdrh 
3212f999a67Sdrh /*
3222f999a67Sdrh ** Usage:    sqlite3_realloc  PRIOR  NBYTES
3232f999a67Sdrh **
3242f999a67Sdrh ** Raw test interface for sqlite3_realloc().
3252f999a67Sdrh */
3262f999a67Sdrh static int test_realloc(
3272f999a67Sdrh   void * clientData,
3282f999a67Sdrh   Tcl_Interp *interp,
3292f999a67Sdrh   int objc,
3302f999a67Sdrh   Tcl_Obj *CONST objv[]
3312f999a67Sdrh ){
3322f999a67Sdrh   int nByte;
3332f999a67Sdrh   void *pPrior, *p;
3342f999a67Sdrh   char zOut[100];
3352f999a67Sdrh   if( objc!=3 ){
3362f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
3372f999a67Sdrh     return TCL_ERROR;
3382f999a67Sdrh   }
3392f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
3402f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
3412f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3422f999a67Sdrh     return TCL_ERROR;
3432f999a67Sdrh   }
3442f999a67Sdrh   p = sqlite3_realloc(pPrior, (unsigned)nByte);
3452f999a67Sdrh   pointerToText(p, zOut);
3462f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
3472f999a67Sdrh   return TCL_OK;
3482f999a67Sdrh }
3492f999a67Sdrh 
3502f999a67Sdrh /*
3512f999a67Sdrh ** Usage:    sqlite3_free  PRIOR
3522f999a67Sdrh **
3532f999a67Sdrh ** Raw test interface for sqlite3_free().
3542f999a67Sdrh */
3552f999a67Sdrh static int test_free(
3562f999a67Sdrh   void * clientData,
3572f999a67Sdrh   Tcl_Interp *interp,
3582f999a67Sdrh   int objc,
3592f999a67Sdrh   Tcl_Obj *CONST objv[]
3602f999a67Sdrh ){
3612f999a67Sdrh   void *pPrior;
3622f999a67Sdrh   if( objc!=2 ){
3632f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
3642f999a67Sdrh     return TCL_ERROR;
3652f999a67Sdrh   }
3662f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
3672f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3682f999a67Sdrh     return TCL_ERROR;
3692f999a67Sdrh   }
3702f999a67Sdrh   sqlite3_free(pPrior);
3712f999a67Sdrh   return TCL_OK;
3722f999a67Sdrh }
3732f999a67Sdrh 
3742f999a67Sdrh /*
3759c7a60dfSdrh ** These routines are in test_hexio.c
3769c7a60dfSdrh */
3779c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *);
3789c7a60dfSdrh int sqlite3TestBinToHex(char*,int);
3799c7a60dfSdrh 
3809c7a60dfSdrh /*
3819c7a60dfSdrh ** Usage:    memset  ADDRESS  SIZE  HEX
3829c7a60dfSdrh **
3839c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a
3849c7a60dfSdrh ** specified hex pattern.
3859c7a60dfSdrh */
3869c7a60dfSdrh static int test_memset(
3879c7a60dfSdrh   void * clientData,
3889c7a60dfSdrh   Tcl_Interp *interp,
3899c7a60dfSdrh   int objc,
3909c7a60dfSdrh   Tcl_Obj *CONST objv[]
3919c7a60dfSdrh ){
3929c7a60dfSdrh   void *p;
3939c7a60dfSdrh   int size, n, i;
3949c7a60dfSdrh   char *zHex;
3959c7a60dfSdrh   char *zOut;
3969c7a60dfSdrh   char zBin[100];
3979c7a60dfSdrh 
3989c7a60dfSdrh   if( objc!=4 ){
3999c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
4009c7a60dfSdrh     return TCL_ERROR;
4019c7a60dfSdrh   }
4029c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
4039c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
4049c7a60dfSdrh     return TCL_ERROR;
4059c7a60dfSdrh   }
4069c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
4079c7a60dfSdrh     return TCL_ERROR;
4089c7a60dfSdrh   }
4099c7a60dfSdrh   if( size<=0 ){
4109c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
4119c7a60dfSdrh     return TCL_ERROR;
4129c7a60dfSdrh   }
4139c7a60dfSdrh   zHex = Tcl_GetStringFromObj(objv[3], &n);
4149c7a60dfSdrh   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
4159c7a60dfSdrh   n = sqlite3TestHexToBin(zHex, n, zBin);
4169c7a60dfSdrh   if( n==0 ){
4179c7a60dfSdrh     Tcl_AppendResult(interp, "no data", (char*)0);
4189c7a60dfSdrh     return TCL_ERROR;
4199c7a60dfSdrh   }
4209c7a60dfSdrh   zOut = p;
4219c7a60dfSdrh   for(i=0; i<size; i++){
4229c7a60dfSdrh     zOut[i] = zBin[i%n];
4239c7a60dfSdrh   }
4249c7a60dfSdrh   return TCL_OK;
4259c7a60dfSdrh }
4269c7a60dfSdrh 
4279c7a60dfSdrh /*
4289c7a60dfSdrh ** Usage:    memget  ADDRESS  SIZE
4299c7a60dfSdrh **
4309c7a60dfSdrh ** Return memory as hexadecimal text.
4319c7a60dfSdrh */
4329c7a60dfSdrh static int test_memget(
4339c7a60dfSdrh   void * clientData,
4349c7a60dfSdrh   Tcl_Interp *interp,
4359c7a60dfSdrh   int objc,
4369c7a60dfSdrh   Tcl_Obj *CONST objv[]
4379c7a60dfSdrh ){
4389c7a60dfSdrh   void *p;
4399c7a60dfSdrh   int size, n;
4409c7a60dfSdrh   char *zBin;
4419c7a60dfSdrh   char zHex[100];
4429c7a60dfSdrh 
4439c7a60dfSdrh   if( objc!=3 ){
4449c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
4459c7a60dfSdrh     return TCL_ERROR;
4469c7a60dfSdrh   }
4479c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
4489c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
4499c7a60dfSdrh     return TCL_ERROR;
4509c7a60dfSdrh   }
4519c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
4529c7a60dfSdrh     return TCL_ERROR;
4539c7a60dfSdrh   }
4549c7a60dfSdrh   if( size<=0 ){
4559c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
4569c7a60dfSdrh     return TCL_ERROR;
4579c7a60dfSdrh   }
4589c7a60dfSdrh   zBin = p;
4599c7a60dfSdrh   while( size>0 ){
4609c7a60dfSdrh     if( size>(sizeof(zHex)-1)/2 ){
4619c7a60dfSdrh       n = (sizeof(zHex)-1)/2;
4629c7a60dfSdrh     }else{
4639c7a60dfSdrh       n = size;
4649c7a60dfSdrh     }
4659c7a60dfSdrh     memcpy(zHex, zBin, n);
4669c7a60dfSdrh     zBin += n;
4679c7a60dfSdrh     size -= n;
4689c7a60dfSdrh     sqlite3TestBinToHex(zHex, n);
4699c7a60dfSdrh     Tcl_AppendResult(interp, zHex, (char*)0);
4709c7a60dfSdrh   }
4719c7a60dfSdrh   return TCL_OK;
4729c7a60dfSdrh }
4739c7a60dfSdrh 
4749c7a60dfSdrh /*
4752f999a67Sdrh ** Usage:    sqlite3_memory_used
4762f999a67Sdrh **
4772f999a67Sdrh ** Raw test interface for sqlite3_memory_used().
4782f999a67Sdrh */
4792f999a67Sdrh static int test_memory_used(
4802f999a67Sdrh   void * clientData,
4812f999a67Sdrh   Tcl_Interp *interp,
4822f999a67Sdrh   int objc,
4832f999a67Sdrh   Tcl_Obj *CONST objv[]
4842f999a67Sdrh ){
4852f999a67Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
4862f999a67Sdrh   return TCL_OK;
4872f999a67Sdrh }
4882f999a67Sdrh 
4892f999a67Sdrh /*
4902f999a67Sdrh ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
4912f999a67Sdrh **
4922f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater().
4932f999a67Sdrh */
4942f999a67Sdrh static int test_memory_highwater(
4952f999a67Sdrh   void * clientData,
4962f999a67Sdrh   Tcl_Interp *interp,
4972f999a67Sdrh   int objc,
4982f999a67Sdrh   Tcl_Obj *CONST objv[]
4992f999a67Sdrh ){
5002f999a67Sdrh   int resetFlag = 0;
5012f999a67Sdrh   if( objc!=1 && objc!=2 ){
5022f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
5032f999a67Sdrh     return TCL_ERROR;
5042f999a67Sdrh   }
5052f999a67Sdrh   if( objc==2 ){
5062f999a67Sdrh     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
5072f999a67Sdrh   }
5082f999a67Sdrh   Tcl_SetObjResult(interp,
5092f999a67Sdrh      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
5102f999a67Sdrh   return TCL_OK;
5112f999a67Sdrh }
5122f999a67Sdrh 
5132f999a67Sdrh /*
5142f999a67Sdrh ** Usage:    sqlite3_memdebug_backtrace DEPTH
5152f999a67Sdrh **
5162f999a67Sdrh ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
5172f999a67Sdrh ** then this routine is a no-op.
5182f999a67Sdrh */
5192f999a67Sdrh static int test_memdebug_backtrace(
5202f999a67Sdrh   void * clientData,
5212f999a67Sdrh   Tcl_Interp *interp,
5222f999a67Sdrh   int objc,
5232f999a67Sdrh   Tcl_Obj *CONST objv[]
5242f999a67Sdrh ){
5252f999a67Sdrh   int depth;
5262f999a67Sdrh   if( objc!=2 ){
5272f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
5282f999a67Sdrh     return TCL_ERROR;
5292f999a67Sdrh   }
5302f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
5312f999a67Sdrh #ifdef SQLITE_MEMDEBUG
5322f999a67Sdrh   {
53349e4fd71Sdrh     extern void sqlite3MemdebugBacktrace(int);
53449e4fd71Sdrh     sqlite3MemdebugBacktrace(depth);
5352f999a67Sdrh   }
5362f999a67Sdrh #endif
5372f999a67Sdrh   return TCL_OK;
5382f999a67Sdrh }
5392f999a67Sdrh 
5402f999a67Sdrh /*
5412f999a67Sdrh ** Usage:    sqlite3_memdebug_dump  FILENAME
5422f999a67Sdrh **
5432f999a67Sdrh ** Write a summary of unfreed memory to FILENAME.
5442f999a67Sdrh */
5452f999a67Sdrh static int test_memdebug_dump(
5462f999a67Sdrh   void * clientData,
5472f999a67Sdrh   Tcl_Interp *interp,
5482f999a67Sdrh   int objc,
5492f999a67Sdrh   Tcl_Obj *CONST objv[]
5502f999a67Sdrh ){
5512f999a67Sdrh   if( objc!=2 ){
5522f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
5532f999a67Sdrh     return TCL_ERROR;
5542f999a67Sdrh   }
5552d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
5562d7636e2Sdrh      || defined(SQLITE_POW2_MEMORY_SIZE)
5572f999a67Sdrh   {
55849e4fd71Sdrh     extern void sqlite3MemdebugDump(const char*);
55949e4fd71Sdrh     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
5602f999a67Sdrh   }
5612f999a67Sdrh #endif
5622f999a67Sdrh   return TCL_OK;
5632f999a67Sdrh }
5642f999a67Sdrh 
565a7a8e14bSdanielk1977 /*
566a7a8e14bSdanielk1977 ** Usage:    sqlite3_memdebug_malloc_count
567a7a8e14bSdanielk1977 **
568a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called.
569a7a8e14bSdanielk1977 */
570a7a8e14bSdanielk1977 static int test_memdebug_malloc_count(
571a7a8e14bSdanielk1977   void * clientData,
572a7a8e14bSdanielk1977   Tcl_Interp *interp,
573a7a8e14bSdanielk1977   int objc,
574a7a8e14bSdanielk1977   Tcl_Obj *CONST objv[]
575a7a8e14bSdanielk1977 ){
576a7a8e14bSdanielk1977   int nMalloc = -1;
577a7a8e14bSdanielk1977   if( objc!=1 ){
578a7a8e14bSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
579a7a8e14bSdanielk1977     return TCL_ERROR;
580a7a8e14bSdanielk1977   }
581a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG)
582a7a8e14bSdanielk1977   {
58349e4fd71Sdrh     extern int sqlite3MemdebugMallocCount();
58449e4fd71Sdrh     nMalloc = sqlite3MemdebugMallocCount();
585a7a8e14bSdanielk1977   }
586a7a8e14bSdanielk1977 #endif
587a7a8e14bSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
588a7a8e14bSdanielk1977   return TCL_OK;
589a7a8e14bSdanielk1977 }
590a7a8e14bSdanielk1977 
5912f999a67Sdrh 
5922f999a67Sdrh /*
593a1644fd8Sdanielk1977 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
594a1644fd8Sdanielk1977 **
595a1644fd8Sdanielk1977 ** where options are:
596a1644fd8Sdanielk1977 **
597643167ffSdrh **     -repeat    <count>
598a1644fd8Sdanielk1977 **     -benigncnt <varname>
5990e6f1546Sdrh **
6000e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes.
601643167ffSdrh ** If a repeat count is specified, the fault is repeated that many
602643167ffSdrh ** times.
6030e6f1546Sdrh **
6040e6f1546Sdrh ** Each call to this routine overrides the prior counter value.
6050e6f1546Sdrh ** This routine returns the number of simulated failures that have
6060e6f1546Sdrh ** happened since the previous call to this routine.
6070e6f1546Sdrh **
6080e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1.
6090e6f1546Sdrh */
6100e6f1546Sdrh static int test_memdebug_fail(
6110e6f1546Sdrh   void * clientData,
6120e6f1546Sdrh   Tcl_Interp *interp,
6130e6f1546Sdrh   int objc,
6140e6f1546Sdrh   Tcl_Obj *CONST objv[]
6150e6f1546Sdrh ){
616a1644fd8Sdanielk1977   int ii;
6170e6f1546Sdrh   int iFail;
618643167ffSdrh   int nRepeat = 1;
619a1644fd8Sdanielk1977   Tcl_Obj *pBenignCnt = 0;
620643167ffSdrh   int nBenign;
6210e6f1546Sdrh   int nFail = 0;
622a1644fd8Sdanielk1977 
623a1644fd8Sdanielk1977   if( objc<2 ){
624a1644fd8Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
6250e6f1546Sdrh     return TCL_ERROR;
6260e6f1546Sdrh   }
6270e6f1546Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
628a1644fd8Sdanielk1977 
629a1644fd8Sdanielk1977   for(ii=2; ii<objc; ii+=2){
630a1644fd8Sdanielk1977     int nOption;
631a1644fd8Sdanielk1977     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
632a1644fd8Sdanielk1977     char *zErr = 0;
633a1644fd8Sdanielk1977 
634a1644fd8Sdanielk1977     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
635a1644fd8Sdanielk1977       if( ii==(objc-1) ){
636a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
637ed138fb3Sdrh       }else{
638643167ffSdrh         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
639a1644fd8Sdanielk1977           return TCL_ERROR;
640ed138fb3Sdrh         }
641a1644fd8Sdanielk1977       }
642a1644fd8Sdanielk1977     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
643a1644fd8Sdanielk1977       if( ii==(objc-1) ){
644a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
645a1644fd8Sdanielk1977       }else{
646a1644fd8Sdanielk1977         pBenignCnt = objv[ii+1];
647a1644fd8Sdanielk1977       }
648a1644fd8Sdanielk1977     }else{
649a1644fd8Sdanielk1977       zErr = "unknown option: ";
650a1644fd8Sdanielk1977     }
651a1644fd8Sdanielk1977 
652a1644fd8Sdanielk1977     if( zErr ){
653a1644fd8Sdanielk1977       Tcl_AppendResult(interp, zErr, zOption, 0);
654a1644fd8Sdanielk1977       return TCL_ERROR;
655a1644fd8Sdanielk1977     }
656a1644fd8Sdanielk1977   }
657a1644fd8Sdanielk1977 
658ef05f2dfSdanielk1977   nBenign = faultsimBenignFailures();
659ef05f2dfSdanielk1977   nFail = faultsimFailures();
660ef05f2dfSdanielk1977   faultsimConfig(iFail, nRepeat);
661ef05f2dfSdanielk1977 
662a1644fd8Sdanielk1977   if( pBenignCnt ){
663643167ffSdrh     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
664a1644fd8Sdanielk1977   }
6650e6f1546Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
6660e6f1546Sdrh   return TCL_OK;
6670e6f1546Sdrh }
6680e6f1546Sdrh 
669cd03724cSdanielk1977 /*
670cd03724cSdanielk1977 ** Usage:    sqlite3_memdebug_pending
671cd03724cSdanielk1977 **
672cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a
673cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that
674cd03724cSdanielk1977 ** no malloc() failure is scheduled.
675cd03724cSdanielk1977 */
676cd03724cSdanielk1977 static int test_memdebug_pending(
677cd03724cSdanielk1977   void * clientData,
678cd03724cSdanielk1977   Tcl_Interp *interp,
679cd03724cSdanielk1977   int objc,
680cd03724cSdanielk1977   Tcl_Obj *CONST objv[]
681cd03724cSdanielk1977 ){
6825efaf070Sdrh   int nPending;
683cd03724cSdanielk1977   if( objc!=1 ){
684cd03724cSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
685cd03724cSdanielk1977     return TCL_ERROR;
686cd03724cSdanielk1977   }
687ef05f2dfSdanielk1977   nPending = faultsimPending();
688ed13d98cSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
689cd03724cSdanielk1977   return TCL_OK;
690cd03724cSdanielk1977 }
691cd03724cSdanielk1977 
6920e6f1546Sdrh 
6930e6f1546Sdrh /*
6944a50aac5Sdrh ** Usage:    sqlite3_memdebug_settitle TITLE
6954a50aac5Sdrh **
6964a50aac5Sdrh ** Set a title string stored with each allocation.  The TITLE is
6974a50aac5Sdrh ** typically the name of the test that was running when the
6984a50aac5Sdrh ** allocation occurred.  The TITLE is stored with the allocation
6994a50aac5Sdrh ** and can be used to figure out which tests are leaking memory.
7004a50aac5Sdrh **
7014a50aac5Sdrh ** Each title overwrite the previous.
7024a50aac5Sdrh */
7034a50aac5Sdrh static int test_memdebug_settitle(
7044a50aac5Sdrh   void * clientData,
7054a50aac5Sdrh   Tcl_Interp *interp,
7064a50aac5Sdrh   int objc,
7074a50aac5Sdrh   Tcl_Obj *CONST objv[]
7084a50aac5Sdrh ){
7094a50aac5Sdrh   const char *zTitle;
7104a50aac5Sdrh   if( objc!=2 ){
7114a50aac5Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
7124a50aac5Sdrh     return TCL_ERROR;
7134a50aac5Sdrh   }
7144a50aac5Sdrh   zTitle = Tcl_GetString(objv[1]);
7154a50aac5Sdrh #ifdef SQLITE_MEMDEBUG
7164a50aac5Sdrh   {
71749e4fd71Sdrh     extern int sqlite3MemdebugSettitle(const char*);
71849e4fd71Sdrh     sqlite3MemdebugSettitle(zTitle);
7194a50aac5Sdrh   }
7204a50aac5Sdrh #endif
7214a50aac5Sdrh   return TCL_OK;
7224a50aac5Sdrh }
7234a50aac5Sdrh 
724cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES 10
7256f332c18Sdanielk1977 static Tcl_HashTable aMallocLog;
7266f332c18Sdanielk1977 static int mallocLogEnabled = 0;
7276f332c18Sdanielk1977 
7286f332c18Sdanielk1977 typedef struct MallocLog MallocLog;
7296f332c18Sdanielk1977 struct MallocLog {
7306f332c18Sdanielk1977   int nCall;
7316f332c18Sdanielk1977   int nByte;
7326f332c18Sdanielk1977 };
7336f332c18Sdanielk1977 
734afdd23a4Sshane #ifdef SQLITE_MEMDEBUG
7356f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
7366f332c18Sdanielk1977   if( mallocLogEnabled ){
7376f332c18Sdanielk1977     MallocLog *pLog;
7386f332c18Sdanielk1977     Tcl_HashEntry *pEntry;
7396f332c18Sdanielk1977     int isNew;
7406f332c18Sdanielk1977 
7416f332c18Sdanielk1977     int aKey[MALLOC_LOG_FRAMES];
7426f332c18Sdanielk1977     int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
7436f332c18Sdanielk1977 
7446f332c18Sdanielk1977     memset(aKey, 0, nKey);
7456f332c18Sdanielk1977     if( (sizeof(void*)*nFrame)<nKey ){
7466f332c18Sdanielk1977       nKey = nFrame*sizeof(void*);
7476f332c18Sdanielk1977     }
7486f332c18Sdanielk1977     memcpy(aKey, aFrame, nKey);
7496f332c18Sdanielk1977 
7506f332c18Sdanielk1977     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
7516f332c18Sdanielk1977     if( isNew ){
7526f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
7536f332c18Sdanielk1977       memset(pLog, 0, sizeof(MallocLog));
7546f332c18Sdanielk1977       Tcl_SetHashValue(pEntry, (ClientData)pLog);
7556f332c18Sdanielk1977     }else{
7566f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
7576f332c18Sdanielk1977     }
7586f332c18Sdanielk1977 
7596f332c18Sdanielk1977     pLog->nCall++;
7606f332c18Sdanielk1977     pLog->nByte += nByte;
7616f332c18Sdanielk1977   }
7626f332c18Sdanielk1977 }
763afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */
7646f332c18Sdanielk1977 
7655f096135Sdanielk1977 static void test_memdebug_log_clear(){
766dbdc4d49Sdanielk1977   Tcl_HashSearch search;
767dbdc4d49Sdanielk1977   Tcl_HashEntry *pEntry;
768dbdc4d49Sdanielk1977   for(
769dbdc4d49Sdanielk1977     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
770dbdc4d49Sdanielk1977     pEntry;
771dbdc4d49Sdanielk1977     pEntry=Tcl_NextHashEntry(&search)
772dbdc4d49Sdanielk1977   ){
773dbdc4d49Sdanielk1977     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
774dbdc4d49Sdanielk1977     Tcl_Free((char *)pLog);
775dbdc4d49Sdanielk1977   }
776dbdc4d49Sdanielk1977   Tcl_DeleteHashTable(&aMallocLog);
777dbdc4d49Sdanielk1977   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
778dbdc4d49Sdanielk1977 }
779dbdc4d49Sdanielk1977 
7806f332c18Sdanielk1977 static int test_memdebug_log(
7816f332c18Sdanielk1977   void * clientData,
7826f332c18Sdanielk1977   Tcl_Interp *interp,
7836f332c18Sdanielk1977   int objc,
7846f332c18Sdanielk1977   Tcl_Obj *CONST objv[]
7856f332c18Sdanielk1977 ){
7866f332c18Sdanielk1977   static int isInit = 0;
7876f332c18Sdanielk1977   int iSub;
7886f332c18Sdanielk1977 
789dbdc4d49Sdanielk1977   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
790dbdc4d49Sdanielk1977   enum MB_enum {
791dbdc4d49Sdanielk1977       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
792dbdc4d49Sdanielk1977   };
7936f332c18Sdanielk1977 
7946f332c18Sdanielk1977   if( !isInit ){
7956f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG
7966f332c18Sdanielk1977     extern void sqlite3MemdebugBacktraceCallback(
7976f332c18Sdanielk1977         void (*xBacktrace)(int, int, void **));
7986f332c18Sdanielk1977     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
7996f332c18Sdanielk1977 #endif
8006f332c18Sdanielk1977     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
8016f332c18Sdanielk1977     isInit = 1;
8026f332c18Sdanielk1977   }
8036f332c18Sdanielk1977 
8046f332c18Sdanielk1977   if( objc<2 ){
8056f332c18Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
8066f332c18Sdanielk1977   }
8076f332c18Sdanielk1977   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
8086f332c18Sdanielk1977     return TCL_ERROR;
8096f332c18Sdanielk1977   }
8106f332c18Sdanielk1977 
8116f332c18Sdanielk1977   switch( (enum MB_enum)iSub ){
8126f332c18Sdanielk1977     case MB_LOG_START:
8136f332c18Sdanielk1977       mallocLogEnabled = 1;
8146f332c18Sdanielk1977       break;
8156f332c18Sdanielk1977     case MB_LOG_STOP:
8166f332c18Sdanielk1977       mallocLogEnabled = 0;
8176f332c18Sdanielk1977       break;
8186f332c18Sdanielk1977     case MB_LOG_DUMP: {
8196f332c18Sdanielk1977       Tcl_HashSearch search;
8206f332c18Sdanielk1977       Tcl_HashEntry *pEntry;
8216f332c18Sdanielk1977       Tcl_Obj *pRet = Tcl_NewObj();
8226f332c18Sdanielk1977 
8236f332c18Sdanielk1977       assert(sizeof(int)==sizeof(void*));
8246f332c18Sdanielk1977 
8256f332c18Sdanielk1977       for(
8266f332c18Sdanielk1977         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
8276f332c18Sdanielk1977         pEntry;
8286f332c18Sdanielk1977         pEntry=Tcl_NextHashEntry(&search)
8296f332c18Sdanielk1977       ){
8306f332c18Sdanielk1977         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
8316f332c18Sdanielk1977         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
8326f332c18Sdanielk1977         int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
8336f332c18Sdanielk1977         int ii;
8346f332c18Sdanielk1977 
8356f332c18Sdanielk1977         apElem[0] = Tcl_NewIntObj(pLog->nCall);
8366f332c18Sdanielk1977         apElem[1] = Tcl_NewIntObj(pLog->nByte);
8376f332c18Sdanielk1977         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
8386f332c18Sdanielk1977           apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
8396f332c18Sdanielk1977         }
8406f332c18Sdanielk1977 
8416f332c18Sdanielk1977         Tcl_ListObjAppendElement(interp, pRet,
8426f332c18Sdanielk1977             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
8436f332c18Sdanielk1977         );
8446f332c18Sdanielk1977       }
8456f332c18Sdanielk1977 
8466f332c18Sdanielk1977       Tcl_SetObjResult(interp, pRet);
8476f332c18Sdanielk1977       break;
8486f332c18Sdanielk1977     }
8496f332c18Sdanielk1977     case MB_LOG_CLEAR: {
850dbdc4d49Sdanielk1977       test_memdebug_log_clear();
851dbdc4d49Sdanielk1977       break;
8526f332c18Sdanielk1977     }
853dbdc4d49Sdanielk1977 
854dbdc4d49Sdanielk1977     case MB_LOG_SYNC: {
855b940492eSdrh #ifdef SQLITE_MEMDEBUG
856dbdc4d49Sdanielk1977       extern void sqlite3MemdebugSync();
857dbdc4d49Sdanielk1977       test_memdebug_log_clear();
858dbdc4d49Sdanielk1977       mallocLogEnabled = 1;
859dbdc4d49Sdanielk1977       sqlite3MemdebugSync();
860b940492eSdrh #endif
861dbdc4d49Sdanielk1977       break;
8626f332c18Sdanielk1977     }
8636f332c18Sdanielk1977   }
8646f332c18Sdanielk1977 
8656f332c18Sdanielk1977   return TCL_OK;
8666f332c18Sdanielk1977 }
8674a50aac5Sdrh 
8684a50aac5Sdrh /*
8699ac3fe97Sdrh ** Usage:    sqlite3_config_scratch SIZE N
8709ac3fe97Sdrh **
8719ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
8729ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
8739ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size.
8749ac3fe97Sdrh ** The revised value of N is returned.
8759ac3fe97Sdrh **
8769ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
8779ac3fe97Sdrh */
8789ac3fe97Sdrh static int test_config_scratch(
8799ac3fe97Sdrh   void * clientData,
8809ac3fe97Sdrh   Tcl_Interp *interp,
8819ac3fe97Sdrh   int objc,
8829ac3fe97Sdrh   Tcl_Obj *CONST objv[]
8839ac3fe97Sdrh ){
8849ac3fe97Sdrh   int sz, N, rc;
8859ac3fe97Sdrh   Tcl_Obj *pResult;
8865f4bcf15Sdrh   static char *buf = 0;
8879ac3fe97Sdrh   if( objc!=3 ){
8889ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
8899ac3fe97Sdrh     return TCL_ERROR;
8909ac3fe97Sdrh   }
891f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
892f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
8935f4bcf15Sdrh   free(buf);
8949ac3fe97Sdrh   if( sz<0 ){
8955f4bcf15Sdrh     buf = 0;
8969ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
897f7141990Sdrh   }else{
8986480aad4Sdrh     buf = malloc( sz*N + 1 );
8999ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
9009ac3fe97Sdrh   }
9019ac3fe97Sdrh   pResult = Tcl_NewObj();
9029ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
9039ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
9049ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
9059ac3fe97Sdrh   return TCL_OK;
9069ac3fe97Sdrh }
9079ac3fe97Sdrh 
9089ac3fe97Sdrh /*
9099ac3fe97Sdrh ** Usage:    sqlite3_config_pagecache SIZE N
9109ac3fe97Sdrh **
9119ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
9129ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
9139ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size.
9149ac3fe97Sdrh ** The revised value of N is returned.
9159ac3fe97Sdrh **
9169ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
9179ac3fe97Sdrh */
9189ac3fe97Sdrh static int test_config_pagecache(
9199ac3fe97Sdrh   void * clientData,
9209ac3fe97Sdrh   Tcl_Interp *interp,
9219ac3fe97Sdrh   int objc,
9229ac3fe97Sdrh   Tcl_Obj *CONST objv[]
9239ac3fe97Sdrh ){
9249ac3fe97Sdrh   int sz, N, rc;
9259ac3fe97Sdrh   Tcl_Obj *pResult;
9265f4bcf15Sdrh   static char *buf = 0;
9279ac3fe97Sdrh   if( objc!=3 ){
9289ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
9299ac3fe97Sdrh     return TCL_ERROR;
9309ac3fe97Sdrh   }
931f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
932f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
9335f4bcf15Sdrh   free(buf);
9349ac3fe97Sdrh   if( sz<0 ){
9355f4bcf15Sdrh     buf = 0;
936f7141990Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
937f7141990Sdrh   }else{
9380a60a384Sdrh     buf = malloc( sz*N );
9399ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
9409ac3fe97Sdrh   }
9419ac3fe97Sdrh   pResult = Tcl_NewObj();
9429ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
9439ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
9449ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
9459ac3fe97Sdrh   return TCL_OK;
9469ac3fe97Sdrh }
9479ac3fe97Sdrh 
948f7141990Sdrh /*
949*b232c232Sdrh ** Usage:    sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
950*b232c232Sdrh **
951*b232c232Sdrh ** Set up the alternative test page cache.  Install if INSTALL_FLAG is
952*b232c232Sdrh ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
953*b232c232Sdrh ** is false.  DISCARD_CHANGE is an integer between 0 and 100 inclusive
954*b232c232Sdrh ** which determines the chance of discarding a page when unpinned.  100
955*b232c232Sdrh ** is certainty.  0 is never.  PRNG_SEED is the pseudo-random number generator
956*b232c232Sdrh ** seed.
957*b232c232Sdrh */
958*b232c232Sdrh static int test_alt_pcache(
959*b232c232Sdrh   void * clientData,
960*b232c232Sdrh   Tcl_Interp *interp,
961*b232c232Sdrh   int objc,
962*b232c232Sdrh   Tcl_Obj *CONST objv[]
963*b232c232Sdrh ){
964*b232c232Sdrh   int installFlag;
965*b232c232Sdrh   int discardChance;
966*b232c232Sdrh   int prngSeed;
967*b232c232Sdrh   extern void installTestPCache(int,unsigned,unsigned);
968*b232c232Sdrh   if( objc!=4 ){
969*b232c232Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "INSTALLFLAG DISCARDCHANCE PRNGSEEED");
970*b232c232Sdrh     return TCL_ERROR;
971*b232c232Sdrh   }
972*b232c232Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
973*b232c232Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &discardChance) ) return TCL_ERROR;
974*b232c232Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ) return TCL_ERROR;
975*b232c232Sdrh   if( discardChance<0 || discardChance>100 ){
976*b232c232Sdrh     Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
977*b232c232Sdrh                      (char*)0);
978*b232c232Sdrh     return TCL_ERROR;
979*b232c232Sdrh   }
980*b232c232Sdrh   installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed);
981*b232c232Sdrh   return TCL_OK;
982*b232c232Sdrh }
983*b232c232Sdrh 
984*b232c232Sdrh /*
9858a42cbd3Sdrh ** Usage:    sqlite3_config_memstatus BOOLEAN
9868a42cbd3Sdrh **
9878a42cbd3Sdrh ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
9888a42cbd3Sdrh */
9898a42cbd3Sdrh static int test_config_memstatus(
9908a42cbd3Sdrh   void * clientData,
9918a42cbd3Sdrh   Tcl_Interp *interp,
9928a42cbd3Sdrh   int objc,
9938a42cbd3Sdrh   Tcl_Obj *CONST objv[]
9948a42cbd3Sdrh ){
9958a42cbd3Sdrh   int enable, rc;
9968a42cbd3Sdrh   if( objc!=2 ){
9978a42cbd3Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
9988a42cbd3Sdrh     return TCL_ERROR;
9998a42cbd3Sdrh   }
10008a42cbd3Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
10018a42cbd3Sdrh   rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
10028a42cbd3Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
10038a42cbd3Sdrh   return TCL_OK;
10048a42cbd3Sdrh }
10058a42cbd3Sdrh 
10068a42cbd3Sdrh /*
1007633e6d57Sdrh ** Usage:    sqlite3_config_lookaside  SIZE  COUNT
1008633e6d57Sdrh **
1009633e6d57Sdrh */
1010633e6d57Sdrh static int test_config_lookaside(
1011633e6d57Sdrh   void * clientData,
1012633e6d57Sdrh   Tcl_Interp *interp,
1013633e6d57Sdrh   int objc,
1014633e6d57Sdrh   Tcl_Obj *CONST objv[]
1015633e6d57Sdrh ){
1016633e6d57Sdrh   int rc;
1017633e6d57Sdrh   int sz, cnt;
1018ab7bee89Sdanielk1977   Tcl_Obj *pRet;
1019633e6d57Sdrh   if( objc!=3 ){
1020633e6d57Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1021633e6d57Sdrh     return TCL_ERROR;
1022633e6d57Sdrh   }
1023633e6d57Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1024633e6d57Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1025ab7bee89Sdanielk1977   pRet = Tcl_NewObj();
1026ab7bee89Sdanielk1977   Tcl_ListObjAppendElement(
1027ab7bee89Sdanielk1977       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1028ab7bee89Sdanielk1977   );
1029ab7bee89Sdanielk1977   Tcl_ListObjAppendElement(
1030ab7bee89Sdanielk1977       interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1031ab7bee89Sdanielk1977   );
1032633e6d57Sdrh   rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1033ab7bee89Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1034633e6d57Sdrh   return TCL_OK;
1035633e6d57Sdrh }
1036633e6d57Sdrh 
1037633e6d57Sdrh 
1038633e6d57Sdrh /*
1039e9d1c720Sdrh ** Usage:    sqlite3_db_config_lookaside  CONNECTION  BUFID  SIZE  COUNT
1040633e6d57Sdrh **
1041e9d1c720Sdrh ** There are two static buffers with BUFID 1 and 2.   Each static buffer
1042e9d1c720Sdrh ** is 10KB in size.  A BUFID of 0 indicates that the buffer should be NULL
1043e9d1c720Sdrh ** which will cause sqlite3_db_config() to allocate space on its own.
1044633e6d57Sdrh */
1045633e6d57Sdrh static int test_db_config_lookaside(
1046633e6d57Sdrh   void * clientData,
1047633e6d57Sdrh   Tcl_Interp *interp,
1048633e6d57Sdrh   int objc,
1049633e6d57Sdrh   Tcl_Obj *CONST objv[]
1050633e6d57Sdrh ){
1051633e6d57Sdrh   int rc;
1052633e6d57Sdrh   int sz, cnt;
1053633e6d57Sdrh   sqlite3 *db;
1054e9d1c720Sdrh   int bufid;
1055e9d1c720Sdrh   static char azBuf[2][10000];
1056633e6d57Sdrh   int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1057e9d1c720Sdrh   if( objc!=5 ){
1058e9d1c720Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1059633e6d57Sdrh     return TCL_ERROR;
1060633e6d57Sdrh   }
1061633e6d57Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1062e9d1c720Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1063e9d1c720Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1064e9d1c720Sdrh   if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1065e9d1c720Sdrh   if( bufid==0 ){
1066e9d1c720Sdrh     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
1067e9d1c720Sdrh   }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1068e9d1c720Sdrh     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1069e9d1c720Sdrh   }else{
1070e9d1c720Sdrh     Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1071e9d1c720Sdrh     return TCL_ERROR;
1072e9d1c720Sdrh   }
1073633e6d57Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1074633e6d57Sdrh   return TCL_OK;
1075633e6d57Sdrh }
1076633e6d57Sdrh 
1077633e6d57Sdrh /*
1078c66c0e14Sdanielk1977 ** Usage:
1079c66c0e14Sdanielk1977 **
10808a42cbd3Sdrh **   sqlite3_config_heap NBYTE NMINALLOC
10815099be5eSdanielk1977 */
10825099be5eSdanielk1977 static int test_config_heap(
10835099be5eSdanielk1977   void * clientData,
10845099be5eSdanielk1977   Tcl_Interp *interp,
10855099be5eSdanielk1977   int objc,
10865099be5eSdanielk1977   Tcl_Obj *CONST objv[]
10875099be5eSdanielk1977 ){
10887830cd41Sdrh   static char *zBuf; /* Use this memory */
10897830cd41Sdrh   static int szBuf;  /* Bytes allocated for zBuf */
10905099be5eSdanielk1977   int nByte;         /* Size of buffer to pass to sqlite3_config() */
10915099be5eSdanielk1977   int nMinAlloc;     /* Size of minimum allocation */
10925099be5eSdanielk1977   int rc;            /* Return code of sqlite3_config() */
10935099be5eSdanielk1977 
10945099be5eSdanielk1977   Tcl_Obj * CONST *aArg = &objv[1];
10955099be5eSdanielk1977   int nArg = objc-1;
10965099be5eSdanielk1977 
10975099be5eSdanielk1977   if( nArg!=2 ){
10988a42cbd3Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
10995099be5eSdanielk1977     return TCL_ERROR;
11005099be5eSdanielk1977   }
11015099be5eSdanielk1977   if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
11025099be5eSdanielk1977   if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
11035099be5eSdanielk1977 
11040d84e5b2Sdanielk1977   if( nByte==0 ){
11057830cd41Sdrh     free( zBuf );
11067830cd41Sdrh     zBuf = 0;
11077830cd41Sdrh     szBuf = 0;
11088a42cbd3Sdrh     rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
11090d84e5b2Sdanielk1977   }else{
11107830cd41Sdrh     zBuf = realloc(zBuf, nByte);
11117830cd41Sdrh     szBuf = nByte;
11125099be5eSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
11130d84e5b2Sdanielk1977   }
11145099be5eSdanielk1977 
11155099be5eSdanielk1977   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
11165099be5eSdanielk1977   return TCL_OK;
11175099be5eSdanielk1977 }
11185099be5eSdanielk1977 
11195099be5eSdanielk1977 /*
11206480aad4Sdrh ** tclcmd:     sqlite3_config_error  [DB]
11216480aad4Sdrh **
11226480aad4Sdrh ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
11236480aad4Sdrh ** opcodes and verify that they return errors.
11246480aad4Sdrh */
11256480aad4Sdrh static int test_config_error(
11266480aad4Sdrh   void * clientData,
11276480aad4Sdrh   Tcl_Interp *interp,
11286480aad4Sdrh   int objc,
11296480aad4Sdrh   Tcl_Obj *CONST objv[]
11306480aad4Sdrh ){
11316480aad4Sdrh   sqlite3 *db;
11326480aad4Sdrh   int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
11336480aad4Sdrh 
11346480aad4Sdrh   if( objc!=2 && objc!=1 ){
11356480aad4Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
11366480aad4Sdrh     return TCL_ERROR;
11376480aad4Sdrh   }
11386480aad4Sdrh   if( objc==2 ){
11396480aad4Sdrh     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11406480aad4Sdrh     if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
11416480aad4Sdrh       Tcl_AppendResult(interp,
11426480aad4Sdrh             "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
11436480aad4Sdrh             (char*)0);
11446480aad4Sdrh       return TCL_ERROR;
11456480aad4Sdrh     }
11466480aad4Sdrh   }else{
11476480aad4Sdrh     if( sqlite3_config(99999)!=SQLITE_ERROR ){
11486480aad4Sdrh       Tcl_AppendResult(interp,
11496480aad4Sdrh           "sqlite3_config(99999) does not return SQLITE_ERROR",
11506480aad4Sdrh           (char*)0);
11516480aad4Sdrh       return TCL_ERROR;
11526480aad4Sdrh     }
11536480aad4Sdrh   }
11546480aad4Sdrh   return TCL_OK;
11556480aad4Sdrh }
11566480aad4Sdrh 
11576480aad4Sdrh /*
11585099be5eSdanielk1977 ** Usage:
11595099be5eSdanielk1977 **
1160c66c0e14Sdanielk1977 **   sqlite3_dump_memsys3  FILENAME
1161c66c0e14Sdanielk1977 **   sqlite3_dump_memsys5  FILENAME
116232155ef0Sdanielk1977 **
116332155ef0Sdanielk1977 ** Write a summary of unfreed memsys3 allocations to FILENAME.
116432155ef0Sdanielk1977 */
116532155ef0Sdanielk1977 static int test_dump_memsys3(
116632155ef0Sdanielk1977   void * clientData,
116732155ef0Sdanielk1977   Tcl_Interp *interp,
116832155ef0Sdanielk1977   int objc,
116932155ef0Sdanielk1977   Tcl_Obj *CONST objv[]
117032155ef0Sdanielk1977 ){
117132155ef0Sdanielk1977   if( objc!=2 ){
117232155ef0Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
117332155ef0Sdanielk1977     return TCL_ERROR;
117432155ef0Sdanielk1977   }
1175c66c0e14Sdanielk1977 
1176c66c0e14Sdanielk1977   switch( (int)clientData ){
11770d84e5b2Sdanielk1977     case 3: {
1178c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS3
117932155ef0Sdanielk1977       extern void sqlite3Memsys3Dump(const char*);
118032155ef0Sdanielk1977       sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1181c66c0e14Sdanielk1977       break;
118232155ef0Sdanielk1977 #endif
1183c66c0e14Sdanielk1977     }
11840d84e5b2Sdanielk1977     case 5: {
1185c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS5
1186c66c0e14Sdanielk1977       extern void sqlite3Memsys5Dump(const char*);
1187c66c0e14Sdanielk1977       sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1188c66c0e14Sdanielk1977       break;
1189c66c0e14Sdanielk1977 #endif
1190c66c0e14Sdanielk1977     }
1191c66c0e14Sdanielk1977   }
119232155ef0Sdanielk1977   return TCL_OK;
119332155ef0Sdanielk1977 }
119432155ef0Sdanielk1977 
119532155ef0Sdanielk1977 /*
1196f7141990Sdrh ** Usage:    sqlite3_status  OPCODE  RESETFLAG
1197f7141990Sdrh **
1198f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return
1199f7141990Sdrh ** code, the current value, and the high-water mark value.
1200f7141990Sdrh */
1201f7141990Sdrh static int test_status(
1202f7141990Sdrh   void * clientData,
1203f7141990Sdrh   Tcl_Interp *interp,
1204f7141990Sdrh   int objc,
1205f7141990Sdrh   Tcl_Obj *CONST objv[]
1206f7141990Sdrh ){
1207f7141990Sdrh   int rc, iValue, mxValue;
1208f7141990Sdrh   int i, op, resetFlag;
1209f7141990Sdrh   const char *zOpName;
1210f7141990Sdrh   static const struct {
1211f7141990Sdrh     const char *zName;
1212f7141990Sdrh     int op;
1213f7141990Sdrh   } aOp[] = {
1214f7141990Sdrh     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
1215e50135e2Sdrh     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
1216f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
1217f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
1218e50135e2Sdrh     { "SQLITE_STATUS_PAGECACHE_SIZE",      SQLITE_STATUS_PAGECACHE_SIZE      },
1219f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
1220f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
1221e50135e2Sdrh     { "SQLITE_STATUS_SCRATCH_SIZE",        SQLITE_STATUS_SCRATCH_SIZE        },
1222ec424a5bSdrh     { "SQLITE_STATUS_PARSER_STACK",        SQLITE_STATUS_PARSER_STACK        },
1223f7141990Sdrh   };
1224f7141990Sdrh   Tcl_Obj *pResult;
1225f7141990Sdrh   if( objc!=3 ){
1226f7141990Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1227f7141990Sdrh     return TCL_ERROR;
1228f7141990Sdrh   }
1229f7141990Sdrh   zOpName = Tcl_GetString(objv[1]);
1230f7141990Sdrh   for(i=0; i<ArraySize(aOp); i++){
1231f7141990Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
1232f7141990Sdrh       op = aOp[i].op;
1233f7141990Sdrh       break;
1234f7141990Sdrh     }
1235f7141990Sdrh   }
1236f7141990Sdrh   if( i>=ArraySize(aOp) ){
1237f7141990Sdrh     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1238f7141990Sdrh   }
1239f7141990Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1240af005fbcSdrh   iValue = 0;
1241af005fbcSdrh   mxValue = 0;
1242f7141990Sdrh   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1243f7141990Sdrh   pResult = Tcl_NewObj();
1244f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1245f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1246f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1247f7141990Sdrh   Tcl_SetObjResult(interp, pResult);
1248f7141990Sdrh   return TCL_OK;
1249f7141990Sdrh }
12509ac3fe97Sdrh 
12519ac3fe97Sdrh /*
1252633e6d57Sdrh ** Usage:    sqlite3_db_status  DATABASE  OPCODE  RESETFLAG
1253633e6d57Sdrh **
1254633e6d57Sdrh ** Return a list of three elements which are the sqlite3_db_status() return
1255633e6d57Sdrh ** code, the current value, and the high-water mark value.
1256633e6d57Sdrh */
1257633e6d57Sdrh static int test_db_status(
1258633e6d57Sdrh   void * clientData,
1259633e6d57Sdrh   Tcl_Interp *interp,
1260633e6d57Sdrh   int objc,
1261633e6d57Sdrh   Tcl_Obj *CONST objv[]
1262633e6d57Sdrh ){
1263633e6d57Sdrh   int rc, iValue, mxValue;
1264633e6d57Sdrh   int i, op, resetFlag;
1265633e6d57Sdrh   const char *zOpName;
1266633e6d57Sdrh   sqlite3 *db;
1267633e6d57Sdrh   int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1268633e6d57Sdrh   static const struct {
1269633e6d57Sdrh     const char *zName;
1270633e6d57Sdrh     int op;
1271633e6d57Sdrh   } aOp[] = {
1272633e6d57Sdrh     { "SQLITE_DBSTATUS_LOOKASIDE_USED",    SQLITE_DBSTATUS_LOOKASIDE_USED   },
1273633e6d57Sdrh   };
1274633e6d57Sdrh   Tcl_Obj *pResult;
1275633e6d57Sdrh   if( objc!=4 ){
1276633e6d57Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1277633e6d57Sdrh     return TCL_ERROR;
1278633e6d57Sdrh   }
1279633e6d57Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1280633e6d57Sdrh   zOpName = Tcl_GetString(objv[2]);
1281633e6d57Sdrh   for(i=0; i<ArraySize(aOp); i++){
1282633e6d57Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
1283633e6d57Sdrh       op = aOp[i].op;
1284633e6d57Sdrh       break;
1285633e6d57Sdrh     }
1286633e6d57Sdrh   }
1287633e6d57Sdrh   if( i>=ArraySize(aOp) ){
1288633e6d57Sdrh     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1289633e6d57Sdrh   }
1290633e6d57Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1291633e6d57Sdrh   iValue = 0;
1292633e6d57Sdrh   mxValue = 0;
1293633e6d57Sdrh   rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1294633e6d57Sdrh   pResult = Tcl_NewObj();
1295633e6d57Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1296633e6d57Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1297633e6d57Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1298633e6d57Sdrh   Tcl_SetObjResult(interp, pResult);
1299633e6d57Sdrh   return TCL_OK;
1300633e6d57Sdrh }
1301633e6d57Sdrh 
1302633e6d57Sdrh /*
1303d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN
1304d09414cdSdanielk1977 */
1305d09414cdSdanielk1977 static int test_install_malloc_faultsim(
1306d09414cdSdanielk1977   void * clientData,
1307d09414cdSdanielk1977   Tcl_Interp *interp,
1308d09414cdSdanielk1977   int objc,
1309d09414cdSdanielk1977   Tcl_Obj *CONST objv[]
1310d09414cdSdanielk1977 ){
1311d09414cdSdanielk1977   int rc;
1312d09414cdSdanielk1977   int isInstall;
1313d09414cdSdanielk1977 
1314d09414cdSdanielk1977   if( objc!=2 ){
1315d09414cdSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1316d09414cdSdanielk1977     return TCL_ERROR;
1317d09414cdSdanielk1977   }
1318d09414cdSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1319d09414cdSdanielk1977     return TCL_ERROR;
1320d09414cdSdanielk1977   }
1321ef05f2dfSdanielk1977   rc = faultsimInstall(isInstall);
1322d09414cdSdanielk1977   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1323d09414cdSdanielk1977   return TCL_OK;
1324d09414cdSdanielk1977 }
1325d09414cdSdanielk1977 
1326d09414cdSdanielk1977 /*
13272f999a67Sdrh ** Register commands with the TCL interpreter.
13282f999a67Sdrh */
13292f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){
13302f999a67Sdrh   static struct {
13312f999a67Sdrh      char *zName;
13322f999a67Sdrh      Tcl_ObjCmdProc *xProc;
1333c66c0e14Sdanielk1977      int clientData;
13342f999a67Sdrh   } aObjCmd[] = {
13358a42cbd3Sdrh      { "sqlite3_malloc",             test_malloc                   ,0 },
13368a42cbd3Sdrh      { "sqlite3_realloc",            test_realloc                  ,0 },
13378a42cbd3Sdrh      { "sqlite3_free",               test_free                     ,0 },
13388a42cbd3Sdrh      { "memset",                     test_memset                   ,0 },
13398a42cbd3Sdrh      { "memget",                     test_memget                   ,0 },
13408a42cbd3Sdrh      { "sqlite3_memory_used",        test_memory_used              ,0 },
13418a42cbd3Sdrh      { "sqlite3_memory_highwater",   test_memory_highwater         ,0 },
13428a42cbd3Sdrh      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0 },
13438a42cbd3Sdrh      { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0 },
13448a42cbd3Sdrh      { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0 },
13458a42cbd3Sdrh      { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0 },
13468a42cbd3Sdrh      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0 },
13478a42cbd3Sdrh      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
13488a42cbd3Sdrh      { "sqlite3_memdebug_log",       test_memdebug_log             ,0 },
13498a42cbd3Sdrh      { "sqlite3_config_scratch",     test_config_scratch           ,0 },
13508a42cbd3Sdrh      { "sqlite3_config_pagecache",   test_config_pagecache         ,0 },
1351*b232c232Sdrh      { "sqlite3_config_alt_pcache",  test_alt_pcache               ,0 },
13528a42cbd3Sdrh      { "sqlite3_status",             test_status                   ,0 },
1353633e6d57Sdrh      { "sqlite3_db_status",          test_db_status                ,0 },
13548a42cbd3Sdrh      { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0 },
13555099be5eSdanielk1977      { "sqlite3_config_heap",        test_config_heap              ,0 },
13568a42cbd3Sdrh      { "sqlite3_config_memstatus",   test_config_memstatus         ,0 },
1357633e6d57Sdrh      { "sqlite3_config_lookaside",   test_config_lookaside         ,0 },
13586480aad4Sdrh      { "sqlite3_config_error",       test_config_error             ,0 },
1359633e6d57Sdrh      { "sqlite3_db_config_lookaside",test_db_config_lookaside      ,0 },
13600d84e5b2Sdanielk1977      { "sqlite3_dump_memsys3",       test_dump_memsys3             ,3 },
1361*b232c232Sdrh      { "sqlite3_dump_memsys5",       test_dump_memsys3             ,5 },
13622f999a67Sdrh   };
13632f999a67Sdrh   int i;
13642f999a67Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1365c66c0e14Sdanielk1977     ClientData c = (ClientData)aObjCmd[i].clientData;
1366c66c0e14Sdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
13672f999a67Sdrh   }
13682f999a67Sdrh   return TCL_OK;
13692f999a67Sdrh }
1370ef05f2dfSdanielk1977 #endif
1371