xref: /sqlite-3.40.0/src/test_malloc.c (revision ef05f2df)
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*ef05f2dfSdanielk1977 ** $Id: test_malloc.c,v 1.27 2008/06/20 11:05:38 danielk1977 Exp $
172f999a67Sdrh */
182f999a67Sdrh #include "sqliteInt.h"
192f999a67Sdrh #include "tcl.h"
202f999a67Sdrh #include <stdlib.h>
212f999a67Sdrh #include <string.h>
222f999a67Sdrh #include <assert.h>
232f999a67Sdrh 
24*ef05f2dfSdanielk1977 /*
25*ef05f2dfSdanielk1977 ** This structure is used to encapsulate the global state variables used
26*ef05f2dfSdanielk1977 ** by malloc() fault simulation.
27*ef05f2dfSdanielk1977 */
28*ef05f2dfSdanielk1977 static struct MemFault {
29*ef05f2dfSdanielk1977   int iCountdown;         /* Number of pending successes before a failure */
30*ef05f2dfSdanielk1977   int nRepeat;            /* Number of times to repeat the failure */
31*ef05f2dfSdanielk1977   int nBenign;            /* Number of benign failures seen since last config */
32*ef05f2dfSdanielk1977   int nFail;              /* Number of failures seen since last config */
33*ef05f2dfSdanielk1977   u8 enable;              /* True if enabled */
34*ef05f2dfSdanielk1977   int isInstalled;        /* True if the fault simulation layer is installed */
35*ef05f2dfSdanielk1977   sqlite3_mem_methods m;  /* 'Real' malloc implementation */
36*ef05f2dfSdanielk1977 } memfault;
37*ef05f2dfSdanielk1977 
38*ef05f2dfSdanielk1977 /*
39*ef05f2dfSdanielk1977 ** This routine exists as a place to set a breakpoint that will
40*ef05f2dfSdanielk1977 ** fire on any simulated malloc() failure.
41*ef05f2dfSdanielk1977 */
42*ef05f2dfSdanielk1977 static void sqlite3Fault(void){
43*ef05f2dfSdanielk1977   static int cnt = 0;
44*ef05f2dfSdanielk1977   cnt++;
45*ef05f2dfSdanielk1977 }
46*ef05f2dfSdanielk1977 
47*ef05f2dfSdanielk1977 /*
48*ef05f2dfSdanielk1977 ** Check to see if a fault should be simulated.  Return true to simulate
49*ef05f2dfSdanielk1977 ** the fault.  Return false if the fault should not be simulated.
50*ef05f2dfSdanielk1977 */
51*ef05f2dfSdanielk1977 static int faultsimStep(){
52*ef05f2dfSdanielk1977   if( likely(!memfault.enable) ){
53*ef05f2dfSdanielk1977     return 0;
54*ef05f2dfSdanielk1977   }
55*ef05f2dfSdanielk1977   if( memfault.iCountdown>0 ){
56*ef05f2dfSdanielk1977     memfault.iCountdown--;
57*ef05f2dfSdanielk1977     return 0;
58*ef05f2dfSdanielk1977   }
59*ef05f2dfSdanielk1977   sqlite3Fault();
60*ef05f2dfSdanielk1977   memfault.nFail++;
61*ef05f2dfSdanielk1977   if( sqlite3FaultIsBenign()>0 ){
62*ef05f2dfSdanielk1977     memfault.nBenign++;
63*ef05f2dfSdanielk1977   }
64*ef05f2dfSdanielk1977   memfault.nRepeat--;
65*ef05f2dfSdanielk1977   if( memfault.nRepeat<=0 ){
66*ef05f2dfSdanielk1977     memfault.enable = 0;
67*ef05f2dfSdanielk1977   }
68*ef05f2dfSdanielk1977   return 1;
69*ef05f2dfSdanielk1977 }
70*ef05f2dfSdanielk1977 
71*ef05f2dfSdanielk1977 /*
72*ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
73*ef05f2dfSdanielk1977 ** logic.
74*ef05f2dfSdanielk1977 */
75*ef05f2dfSdanielk1977 static void *faultsimMalloc(int n){
76*ef05f2dfSdanielk1977   void *p = 0;
77*ef05f2dfSdanielk1977   if( !faultsimStep() ){
78*ef05f2dfSdanielk1977     p = memfault.m.xMalloc(n);
79*ef05f2dfSdanielk1977   }
80*ef05f2dfSdanielk1977   return p;
81*ef05f2dfSdanielk1977 }
82*ef05f2dfSdanielk1977 
83*ef05f2dfSdanielk1977 
84*ef05f2dfSdanielk1977 /*
85*ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
86*ef05f2dfSdanielk1977 ** logic.
87*ef05f2dfSdanielk1977 */
88*ef05f2dfSdanielk1977 static void *faultsimRealloc(void *pOld, int n){
89*ef05f2dfSdanielk1977   void *p = 0;
90*ef05f2dfSdanielk1977   if( !faultsimStep() ){
91*ef05f2dfSdanielk1977     p = memfault.m.xRealloc(pOld, n);
92*ef05f2dfSdanielk1977   }
93*ef05f2dfSdanielk1977   return p;
94*ef05f2dfSdanielk1977 }
95*ef05f2dfSdanielk1977 
96*ef05f2dfSdanielk1977 /*
97*ef05f2dfSdanielk1977 ** The following method calls are passed directly through to the underlying
98*ef05f2dfSdanielk1977 ** malloc system:
99*ef05f2dfSdanielk1977 **
100*ef05f2dfSdanielk1977 **     xFree
101*ef05f2dfSdanielk1977 **     xSize
102*ef05f2dfSdanielk1977 **     xRoundup
103*ef05f2dfSdanielk1977 **     xInit
104*ef05f2dfSdanielk1977 **     xShutdown
105*ef05f2dfSdanielk1977 */
106*ef05f2dfSdanielk1977 static void faultsimFree(void *p){
107*ef05f2dfSdanielk1977   memfault.m.xFree(p);
108*ef05f2dfSdanielk1977 }
109*ef05f2dfSdanielk1977 static int faultsimSize(void *p){
110*ef05f2dfSdanielk1977   return memfault.m.xSize(p);
111*ef05f2dfSdanielk1977 }
112*ef05f2dfSdanielk1977 static int faultsimRoundup(int n){
113*ef05f2dfSdanielk1977   return memfault.m.xRoundup(n);
114*ef05f2dfSdanielk1977 }
115*ef05f2dfSdanielk1977 static int faultsimInit(void *p){
116*ef05f2dfSdanielk1977   return memfault.m.xInit(memfault.m.pAppData);
117*ef05f2dfSdanielk1977 }
118*ef05f2dfSdanielk1977 static void faultsimShutdown(void *p){
119*ef05f2dfSdanielk1977   memfault.m.xShutdown(memfault.m.pAppData);
120*ef05f2dfSdanielk1977 }
121*ef05f2dfSdanielk1977 
122*ef05f2dfSdanielk1977 /*
123*ef05f2dfSdanielk1977 ** This routine configures the malloc failure simulation.  After
124*ef05f2dfSdanielk1977 ** calling this routine, the next nDelay mallocs will succeed, followed
125*ef05f2dfSdanielk1977 ** by a block of nRepeat failures, after which malloc() calls will begin
126*ef05f2dfSdanielk1977 ** to succeed again.
127*ef05f2dfSdanielk1977 */
128*ef05f2dfSdanielk1977 static void faultsimConfig(int nDelay, int nRepeat){
129*ef05f2dfSdanielk1977   memfault.iCountdown = nDelay;
130*ef05f2dfSdanielk1977   memfault.nRepeat = nRepeat;
131*ef05f2dfSdanielk1977   memfault.nBenign = 0;
132*ef05f2dfSdanielk1977   memfault.nFail = 0;
133*ef05f2dfSdanielk1977   memfault.enable = nDelay>=0;
134*ef05f2dfSdanielk1977 }
135*ef05f2dfSdanielk1977 
136*ef05f2dfSdanielk1977 /*
137*ef05f2dfSdanielk1977 ** Return the number of faults (both hard and benign faults) that have
138*ef05f2dfSdanielk1977 ** occurred since the injector was last configured.
139*ef05f2dfSdanielk1977 */
140*ef05f2dfSdanielk1977 static int faultsimFailures(void){
141*ef05f2dfSdanielk1977   return memfault.nFail;
142*ef05f2dfSdanielk1977 }
143*ef05f2dfSdanielk1977 
144*ef05f2dfSdanielk1977 /*
145*ef05f2dfSdanielk1977 ** Return the number of benign faults that have occurred since the
146*ef05f2dfSdanielk1977 ** injector was last configured.
147*ef05f2dfSdanielk1977 */
148*ef05f2dfSdanielk1977 static int faultsimBenignFailures(void){
149*ef05f2dfSdanielk1977   return memfault.nBenign;
150*ef05f2dfSdanielk1977 }
151*ef05f2dfSdanielk1977 
152*ef05f2dfSdanielk1977 /*
153*ef05f2dfSdanielk1977 ** Return the number of successes that will occur before the next failure.
154*ef05f2dfSdanielk1977 ** If no failures are scheduled, return -1.
155*ef05f2dfSdanielk1977 */
156*ef05f2dfSdanielk1977 static int faultsimPending(void){
157*ef05f2dfSdanielk1977   if( memfault.enable ){
158*ef05f2dfSdanielk1977     return memfault.iCountdown;
159*ef05f2dfSdanielk1977   }else{
160*ef05f2dfSdanielk1977     return -1;
161*ef05f2dfSdanielk1977   }
162*ef05f2dfSdanielk1977 }
163*ef05f2dfSdanielk1977 
164*ef05f2dfSdanielk1977 /*
165*ef05f2dfSdanielk1977 ** Add or remove the fault-simulation layer using sqlite3_config(). If
166*ef05f2dfSdanielk1977 ** the argument is non-zero, the
167*ef05f2dfSdanielk1977 */
168*ef05f2dfSdanielk1977 static int faultsimInstall(int install){
169*ef05f2dfSdanielk1977   static struct sqlite3_mem_methods m = {
170*ef05f2dfSdanielk1977     faultsimMalloc,                   /* xMalloc */
171*ef05f2dfSdanielk1977     faultsimFree,                     /* xFree */
172*ef05f2dfSdanielk1977     faultsimRealloc,                  /* xRealloc */
173*ef05f2dfSdanielk1977     faultsimSize,                     /* xSize */
174*ef05f2dfSdanielk1977     faultsimRoundup,                  /* xRoundup */
175*ef05f2dfSdanielk1977     faultsimInit,                     /* xInit */
176*ef05f2dfSdanielk1977     faultsimShutdown,                 /* xShutdown */
177*ef05f2dfSdanielk1977     0                                 /* pAppData */
178*ef05f2dfSdanielk1977   };
179*ef05f2dfSdanielk1977   int rc;
180*ef05f2dfSdanielk1977 
181*ef05f2dfSdanielk1977   install = (install ? 1 : 0);
182*ef05f2dfSdanielk1977   assert(memfault.isInstalled==1 || memfault.isInstalled==0);
183*ef05f2dfSdanielk1977 
184*ef05f2dfSdanielk1977   if( install==memfault.isInstalled ){
185*ef05f2dfSdanielk1977     return SQLITE_ERROR;
186*ef05f2dfSdanielk1977   }
187*ef05f2dfSdanielk1977 
188*ef05f2dfSdanielk1977   rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
189*ef05f2dfSdanielk1977   assert(memfault.m.xMalloc);
190*ef05f2dfSdanielk1977   if( rc==SQLITE_OK ){
191*ef05f2dfSdanielk1977     rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
192*ef05f2dfSdanielk1977   }
193*ef05f2dfSdanielk1977 
194*ef05f2dfSdanielk1977   if( rc==SQLITE_OK ){
195*ef05f2dfSdanielk1977     memfault.isInstalled = 1;
196*ef05f2dfSdanielk1977   }
197*ef05f2dfSdanielk1977   return rc;
198*ef05f2dfSdanielk1977 }
199*ef05f2dfSdanielk1977 
200*ef05f2dfSdanielk1977 #ifdef SQLITE_TEST
201*ef05f2dfSdanielk1977 
202*ef05f2dfSdanielk1977 /*
203*ef05f2dfSdanielk1977 ** This function is implemented in test1.c. Returns a pointer to a static
204*ef05f2dfSdanielk1977 ** buffer containing the symbolic SQLite error code that corresponds to
205*ef05f2dfSdanielk1977 ** the least-significant 8-bits of the integer passed as an argument.
206*ef05f2dfSdanielk1977 ** For example:
207*ef05f2dfSdanielk1977 **
208*ef05f2dfSdanielk1977 **   sqlite3TestErrorName(1) -> "SQLITE_ERROR"
209*ef05f2dfSdanielk1977 */
210d09414cdSdanielk1977 const char *sqlite3TestErrorName(int);
211d09414cdSdanielk1977 
2122f999a67Sdrh /*
2132f999a67Sdrh ** Transform pointers to text and back again
2142f999a67Sdrh */
2152f999a67Sdrh static void pointerToText(void *p, char *z){
2162f999a67Sdrh   static const char zHex[] = "0123456789abcdef";
2172f999a67Sdrh   int i, k;
2184a50aac5Sdrh   unsigned int u;
2194a50aac5Sdrh   sqlite3_uint64 n;
2204a50aac5Sdrh   if( sizeof(n)==sizeof(p) ){
2214a50aac5Sdrh     memcpy(&n, &p, sizeof(p));
2224a50aac5Sdrh   }else if( sizeof(u)==sizeof(p) ){
2234a50aac5Sdrh     memcpy(&u, &p, sizeof(u));
2244a50aac5Sdrh     n = u;
2254a50aac5Sdrh   }else{
2264a50aac5Sdrh     assert( 0 );
2274a50aac5Sdrh   }
2282f999a67Sdrh   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
2292f999a67Sdrh     z[k] = zHex[n&0xf];
2302f999a67Sdrh     n >>= 4;
2312f999a67Sdrh   }
2322f999a67Sdrh   z[sizeof(p)*2] = 0;
2332f999a67Sdrh }
2342f999a67Sdrh static int hexToInt(int h){
2352f999a67Sdrh   if( h>='0' && h<='9' ){
2362f999a67Sdrh     return h - '0';
2372f999a67Sdrh   }else if( h>='a' && h<='f' ){
2382f999a67Sdrh     return h - 'a' + 10;
2392f999a67Sdrh   }else{
2402f999a67Sdrh     return -1;
2412f999a67Sdrh   }
2422f999a67Sdrh }
2432f999a67Sdrh static int textToPointer(const char *z, void **pp){
2442f999a67Sdrh   sqlite3_uint64 n = 0;
2452f999a67Sdrh   int i;
2464a50aac5Sdrh   unsigned int u;
2472f999a67Sdrh   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
2482f999a67Sdrh     int v;
2492f999a67Sdrh     v = hexToInt(*z++);
2502f999a67Sdrh     if( v<0 ) return TCL_ERROR;
2512f999a67Sdrh     n = n*16 + v;
2522f999a67Sdrh   }
2532f999a67Sdrh   if( *z!=0 ) return TCL_ERROR;
2544a50aac5Sdrh   if( sizeof(n)==sizeof(*pp) ){
2554a50aac5Sdrh     memcpy(pp, &n, sizeof(n));
2564a50aac5Sdrh   }else if( sizeof(u)==sizeof(*pp) ){
2574a50aac5Sdrh     u = (unsigned int)n;
2584a50aac5Sdrh     memcpy(pp, &u, sizeof(u));
2594a50aac5Sdrh   }else{
2604a50aac5Sdrh     assert( 0 );
2614a50aac5Sdrh   }
2622f999a67Sdrh   return TCL_OK;
2632f999a67Sdrh }
2642f999a67Sdrh 
2652f999a67Sdrh /*
2662f999a67Sdrh ** Usage:    sqlite3_malloc  NBYTES
2672f999a67Sdrh **
2682f999a67Sdrh ** Raw test interface for sqlite3_malloc().
2692f999a67Sdrh */
2702f999a67Sdrh static int test_malloc(
2712f999a67Sdrh   void * clientData,
2722f999a67Sdrh   Tcl_Interp *interp,
2732f999a67Sdrh   int objc,
2742f999a67Sdrh   Tcl_Obj *CONST objv[]
2752f999a67Sdrh ){
2762f999a67Sdrh   int nByte;
2772f999a67Sdrh   void *p;
2782f999a67Sdrh   char zOut[100];
2792f999a67Sdrh   if( objc!=2 ){
2802f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
2812f999a67Sdrh     return TCL_ERROR;
2822f999a67Sdrh   }
2832f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
2842f999a67Sdrh   p = sqlite3_malloc((unsigned)nByte);
2852f999a67Sdrh   pointerToText(p, zOut);
2862f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
2872f999a67Sdrh   return TCL_OK;
2882f999a67Sdrh }
2892f999a67Sdrh 
2902f999a67Sdrh /*
2912f999a67Sdrh ** Usage:    sqlite3_realloc  PRIOR  NBYTES
2922f999a67Sdrh **
2932f999a67Sdrh ** Raw test interface for sqlite3_realloc().
2942f999a67Sdrh */
2952f999a67Sdrh static int test_realloc(
2962f999a67Sdrh   void * clientData,
2972f999a67Sdrh   Tcl_Interp *interp,
2982f999a67Sdrh   int objc,
2992f999a67Sdrh   Tcl_Obj *CONST objv[]
3002f999a67Sdrh ){
3012f999a67Sdrh   int nByte;
3022f999a67Sdrh   void *pPrior, *p;
3032f999a67Sdrh   char zOut[100];
3042f999a67Sdrh   if( objc!=3 ){
3052f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
3062f999a67Sdrh     return TCL_ERROR;
3072f999a67Sdrh   }
3082f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
3092f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
3102f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3112f999a67Sdrh     return TCL_ERROR;
3122f999a67Sdrh   }
3132f999a67Sdrh   p = sqlite3_realloc(pPrior, (unsigned)nByte);
3142f999a67Sdrh   pointerToText(p, zOut);
3152f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
3162f999a67Sdrh   return TCL_OK;
3172f999a67Sdrh }
3182f999a67Sdrh 
3192f999a67Sdrh /*
3202f999a67Sdrh ** Usage:    sqlite3_free  PRIOR
3212f999a67Sdrh **
3222f999a67Sdrh ** Raw test interface for sqlite3_free().
3232f999a67Sdrh */
3242f999a67Sdrh static int test_free(
3252f999a67Sdrh   void * clientData,
3262f999a67Sdrh   Tcl_Interp *interp,
3272f999a67Sdrh   int objc,
3282f999a67Sdrh   Tcl_Obj *CONST objv[]
3292f999a67Sdrh ){
3302f999a67Sdrh   void *pPrior;
3312f999a67Sdrh   if( objc!=2 ){
3322f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
3332f999a67Sdrh     return TCL_ERROR;
3342f999a67Sdrh   }
3352f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
3362f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3372f999a67Sdrh     return TCL_ERROR;
3382f999a67Sdrh   }
3392f999a67Sdrh   sqlite3_free(pPrior);
3402f999a67Sdrh   return TCL_OK;
3412f999a67Sdrh }
3422f999a67Sdrh 
3432f999a67Sdrh /*
3449c7a60dfSdrh ** These routines are in test_hexio.c
3459c7a60dfSdrh */
3469c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *);
3479c7a60dfSdrh int sqlite3TestBinToHex(char*,int);
3489c7a60dfSdrh 
3499c7a60dfSdrh /*
3509c7a60dfSdrh ** Usage:    memset  ADDRESS  SIZE  HEX
3519c7a60dfSdrh **
3529c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a
3539c7a60dfSdrh ** specified hex pattern.
3549c7a60dfSdrh */
3559c7a60dfSdrh static int test_memset(
3569c7a60dfSdrh   void * clientData,
3579c7a60dfSdrh   Tcl_Interp *interp,
3589c7a60dfSdrh   int objc,
3599c7a60dfSdrh   Tcl_Obj *CONST objv[]
3609c7a60dfSdrh ){
3619c7a60dfSdrh   void *p;
3629c7a60dfSdrh   int size, n, i;
3639c7a60dfSdrh   char *zHex;
3649c7a60dfSdrh   char *zOut;
3659c7a60dfSdrh   char zBin[100];
3669c7a60dfSdrh 
3679c7a60dfSdrh   if( objc!=4 ){
3689c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
3699c7a60dfSdrh     return TCL_ERROR;
3709c7a60dfSdrh   }
3719c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
3729c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
3739c7a60dfSdrh     return TCL_ERROR;
3749c7a60dfSdrh   }
3759c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
3769c7a60dfSdrh     return TCL_ERROR;
3779c7a60dfSdrh   }
3789c7a60dfSdrh   if( size<=0 ){
3799c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
3809c7a60dfSdrh     return TCL_ERROR;
3819c7a60dfSdrh   }
3829c7a60dfSdrh   zHex = Tcl_GetStringFromObj(objv[3], &n);
3839c7a60dfSdrh   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
3849c7a60dfSdrh   n = sqlite3TestHexToBin(zHex, n, zBin);
3859c7a60dfSdrh   if( n==0 ){
3869c7a60dfSdrh     Tcl_AppendResult(interp, "no data", (char*)0);
3879c7a60dfSdrh     return TCL_ERROR;
3889c7a60dfSdrh   }
3899c7a60dfSdrh   zOut = p;
3909c7a60dfSdrh   for(i=0; i<size; i++){
3919c7a60dfSdrh     zOut[i] = zBin[i%n];
3929c7a60dfSdrh   }
3939c7a60dfSdrh   return TCL_OK;
3949c7a60dfSdrh }
3959c7a60dfSdrh 
3969c7a60dfSdrh /*
3979c7a60dfSdrh ** Usage:    memget  ADDRESS  SIZE
3989c7a60dfSdrh **
3999c7a60dfSdrh ** Return memory as hexadecimal text.
4009c7a60dfSdrh */
4019c7a60dfSdrh static int test_memget(
4029c7a60dfSdrh   void * clientData,
4039c7a60dfSdrh   Tcl_Interp *interp,
4049c7a60dfSdrh   int objc,
4059c7a60dfSdrh   Tcl_Obj *CONST objv[]
4069c7a60dfSdrh ){
4079c7a60dfSdrh   void *p;
4089c7a60dfSdrh   int size, n;
4099c7a60dfSdrh   char *zBin;
4109c7a60dfSdrh   char zHex[100];
4119c7a60dfSdrh 
4129c7a60dfSdrh   if( objc!=3 ){
4139c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
4149c7a60dfSdrh     return TCL_ERROR;
4159c7a60dfSdrh   }
4169c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
4179c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
4189c7a60dfSdrh     return TCL_ERROR;
4199c7a60dfSdrh   }
4209c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
4219c7a60dfSdrh     return TCL_ERROR;
4229c7a60dfSdrh   }
4239c7a60dfSdrh   if( size<=0 ){
4249c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
4259c7a60dfSdrh     return TCL_ERROR;
4269c7a60dfSdrh   }
4279c7a60dfSdrh   zBin = p;
4289c7a60dfSdrh   while( size>0 ){
4299c7a60dfSdrh     if( size>(sizeof(zHex)-1)/2 ){
4309c7a60dfSdrh       n = (sizeof(zHex)-1)/2;
4319c7a60dfSdrh     }else{
4329c7a60dfSdrh       n = size;
4339c7a60dfSdrh     }
4349c7a60dfSdrh     memcpy(zHex, zBin, n);
4359c7a60dfSdrh     zBin += n;
4369c7a60dfSdrh     size -= n;
4379c7a60dfSdrh     sqlite3TestBinToHex(zHex, n);
4389c7a60dfSdrh     Tcl_AppendResult(interp, zHex, (char*)0);
4399c7a60dfSdrh   }
4409c7a60dfSdrh   return TCL_OK;
4419c7a60dfSdrh }
4429c7a60dfSdrh 
4439c7a60dfSdrh /*
4442f999a67Sdrh ** Usage:    sqlite3_memory_used
4452f999a67Sdrh **
4462f999a67Sdrh ** Raw test interface for sqlite3_memory_used().
4472f999a67Sdrh */
4482f999a67Sdrh static int test_memory_used(
4492f999a67Sdrh   void * clientData,
4502f999a67Sdrh   Tcl_Interp *interp,
4512f999a67Sdrh   int objc,
4522f999a67Sdrh   Tcl_Obj *CONST objv[]
4532f999a67Sdrh ){
4542f999a67Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
4552f999a67Sdrh   return TCL_OK;
4562f999a67Sdrh }
4572f999a67Sdrh 
4582f999a67Sdrh /*
4592f999a67Sdrh ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
4602f999a67Sdrh **
4612f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater().
4622f999a67Sdrh */
4632f999a67Sdrh static int test_memory_highwater(
4642f999a67Sdrh   void * clientData,
4652f999a67Sdrh   Tcl_Interp *interp,
4662f999a67Sdrh   int objc,
4672f999a67Sdrh   Tcl_Obj *CONST objv[]
4682f999a67Sdrh ){
4692f999a67Sdrh   int resetFlag = 0;
4702f999a67Sdrh   if( objc!=1 && objc!=2 ){
4712f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
4722f999a67Sdrh     return TCL_ERROR;
4732f999a67Sdrh   }
4742f999a67Sdrh   if( objc==2 ){
4752f999a67Sdrh     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
4762f999a67Sdrh   }
4772f999a67Sdrh   Tcl_SetObjResult(interp,
4782f999a67Sdrh      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
4792f999a67Sdrh   return TCL_OK;
4802f999a67Sdrh }
4812f999a67Sdrh 
4822f999a67Sdrh /*
4832f999a67Sdrh ** Usage:    sqlite3_memdebug_backtrace DEPTH
4842f999a67Sdrh **
4852f999a67Sdrh ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
4862f999a67Sdrh ** then this routine is a no-op.
4872f999a67Sdrh */
4882f999a67Sdrh static int test_memdebug_backtrace(
4892f999a67Sdrh   void * clientData,
4902f999a67Sdrh   Tcl_Interp *interp,
4912f999a67Sdrh   int objc,
4922f999a67Sdrh   Tcl_Obj *CONST objv[]
4932f999a67Sdrh ){
4942f999a67Sdrh   int depth;
4952f999a67Sdrh   if( objc!=2 ){
4962f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
4972f999a67Sdrh     return TCL_ERROR;
4982f999a67Sdrh   }
4992f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
5002f999a67Sdrh #ifdef SQLITE_MEMDEBUG
5012f999a67Sdrh   {
50249e4fd71Sdrh     extern void sqlite3MemdebugBacktrace(int);
50349e4fd71Sdrh     sqlite3MemdebugBacktrace(depth);
5042f999a67Sdrh   }
5052f999a67Sdrh #endif
5062f999a67Sdrh   return TCL_OK;
5072f999a67Sdrh }
5082f999a67Sdrh 
5092f999a67Sdrh /*
5102f999a67Sdrh ** Usage:    sqlite3_memdebug_dump  FILENAME
5112f999a67Sdrh **
5122f999a67Sdrh ** Write a summary of unfreed memory to FILENAME.
5132f999a67Sdrh */
5142f999a67Sdrh static int test_memdebug_dump(
5152f999a67Sdrh   void * clientData,
5162f999a67Sdrh   Tcl_Interp *interp,
5172f999a67Sdrh   int objc,
5182f999a67Sdrh   Tcl_Obj *CONST objv[]
5192f999a67Sdrh ){
5202f999a67Sdrh   if( objc!=2 ){
5212f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
5222f999a67Sdrh     return TCL_ERROR;
5232f999a67Sdrh   }
5242d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
5252d7636e2Sdrh      || defined(SQLITE_POW2_MEMORY_SIZE)
5262f999a67Sdrh   {
52749e4fd71Sdrh     extern void sqlite3MemdebugDump(const char*);
52849e4fd71Sdrh     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
5292f999a67Sdrh   }
5302f999a67Sdrh #endif
5312f999a67Sdrh   return TCL_OK;
5322f999a67Sdrh }
5332f999a67Sdrh 
534a7a8e14bSdanielk1977 /*
535a7a8e14bSdanielk1977 ** Usage:    sqlite3_memdebug_malloc_count
536a7a8e14bSdanielk1977 **
537a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called.
538a7a8e14bSdanielk1977 */
539a7a8e14bSdanielk1977 static int test_memdebug_malloc_count(
540a7a8e14bSdanielk1977   void * clientData,
541a7a8e14bSdanielk1977   Tcl_Interp *interp,
542a7a8e14bSdanielk1977   int objc,
543a7a8e14bSdanielk1977   Tcl_Obj *CONST objv[]
544a7a8e14bSdanielk1977 ){
545a7a8e14bSdanielk1977   int nMalloc = -1;
546a7a8e14bSdanielk1977   if( objc!=1 ){
547a7a8e14bSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
548a7a8e14bSdanielk1977     return TCL_ERROR;
549a7a8e14bSdanielk1977   }
550a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG)
551a7a8e14bSdanielk1977   {
55249e4fd71Sdrh     extern int sqlite3MemdebugMallocCount();
55349e4fd71Sdrh     nMalloc = sqlite3MemdebugMallocCount();
554a7a8e14bSdanielk1977   }
555a7a8e14bSdanielk1977 #endif
556a7a8e14bSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
557a7a8e14bSdanielk1977   return TCL_OK;
558a7a8e14bSdanielk1977 }
559a7a8e14bSdanielk1977 
5602f999a67Sdrh 
5612f999a67Sdrh /*
562a1644fd8Sdanielk1977 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
563a1644fd8Sdanielk1977 **
564a1644fd8Sdanielk1977 ** where options are:
565a1644fd8Sdanielk1977 **
566643167ffSdrh **     -repeat    <count>
567a1644fd8Sdanielk1977 **     -benigncnt <varname>
5680e6f1546Sdrh **
5690e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes.
570643167ffSdrh ** If a repeat count is specified, the fault is repeated that many
571643167ffSdrh ** times.
5720e6f1546Sdrh **
5730e6f1546Sdrh ** Each call to this routine overrides the prior counter value.
5740e6f1546Sdrh ** This routine returns the number of simulated failures that have
5750e6f1546Sdrh ** happened since the previous call to this routine.
5760e6f1546Sdrh **
5770e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1.
5780e6f1546Sdrh */
5790e6f1546Sdrh static int test_memdebug_fail(
5800e6f1546Sdrh   void * clientData,
5810e6f1546Sdrh   Tcl_Interp *interp,
5820e6f1546Sdrh   int objc,
5830e6f1546Sdrh   Tcl_Obj *CONST objv[]
5840e6f1546Sdrh ){
585a1644fd8Sdanielk1977   int ii;
5860e6f1546Sdrh   int iFail;
587643167ffSdrh   int nRepeat = 1;
588a1644fd8Sdanielk1977   Tcl_Obj *pBenignCnt = 0;
589643167ffSdrh   int nBenign;
5900e6f1546Sdrh   int nFail = 0;
591a1644fd8Sdanielk1977 
592a1644fd8Sdanielk1977   if( objc<2 ){
593a1644fd8Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
5940e6f1546Sdrh     return TCL_ERROR;
5950e6f1546Sdrh   }
5960e6f1546Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
597a1644fd8Sdanielk1977 
598a1644fd8Sdanielk1977   for(ii=2; ii<objc; ii+=2){
599a1644fd8Sdanielk1977     int nOption;
600a1644fd8Sdanielk1977     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
601a1644fd8Sdanielk1977     char *zErr = 0;
602a1644fd8Sdanielk1977 
603a1644fd8Sdanielk1977     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
604a1644fd8Sdanielk1977       if( ii==(objc-1) ){
605a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
606ed138fb3Sdrh       }else{
607643167ffSdrh         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
608a1644fd8Sdanielk1977           return TCL_ERROR;
609ed138fb3Sdrh         }
610a1644fd8Sdanielk1977       }
611a1644fd8Sdanielk1977     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
612a1644fd8Sdanielk1977       if( ii==(objc-1) ){
613a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
614a1644fd8Sdanielk1977       }else{
615a1644fd8Sdanielk1977         pBenignCnt = objv[ii+1];
616a1644fd8Sdanielk1977       }
617a1644fd8Sdanielk1977     }else{
618a1644fd8Sdanielk1977       zErr = "unknown option: ";
619a1644fd8Sdanielk1977     }
620a1644fd8Sdanielk1977 
621a1644fd8Sdanielk1977     if( zErr ){
622a1644fd8Sdanielk1977       Tcl_AppendResult(interp, zErr, zOption, 0);
623a1644fd8Sdanielk1977       return TCL_ERROR;
624a1644fd8Sdanielk1977     }
625a1644fd8Sdanielk1977   }
626a1644fd8Sdanielk1977 
627*ef05f2dfSdanielk1977   nBenign = faultsimBenignFailures();
628*ef05f2dfSdanielk1977   nFail = faultsimFailures();
629*ef05f2dfSdanielk1977   faultsimConfig(iFail, nRepeat);
630*ef05f2dfSdanielk1977 
631a1644fd8Sdanielk1977   if( pBenignCnt ){
632643167ffSdrh     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
633a1644fd8Sdanielk1977   }
6340e6f1546Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
6350e6f1546Sdrh   return TCL_OK;
6360e6f1546Sdrh }
6370e6f1546Sdrh 
638cd03724cSdanielk1977 /*
639cd03724cSdanielk1977 ** Usage:    sqlite3_memdebug_pending
640cd03724cSdanielk1977 **
641cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a
642cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that
643cd03724cSdanielk1977 ** no malloc() failure is scheduled.
644cd03724cSdanielk1977 */
645cd03724cSdanielk1977 static int test_memdebug_pending(
646cd03724cSdanielk1977   void * clientData,
647cd03724cSdanielk1977   Tcl_Interp *interp,
648cd03724cSdanielk1977   int objc,
649cd03724cSdanielk1977   Tcl_Obj *CONST objv[]
650cd03724cSdanielk1977 ){
6515efaf070Sdrh   int nPending;
652cd03724cSdanielk1977   if( objc!=1 ){
653cd03724cSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
654cd03724cSdanielk1977     return TCL_ERROR;
655cd03724cSdanielk1977   }
656*ef05f2dfSdanielk1977   nPending = faultsimPending();
657ed13d98cSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
658cd03724cSdanielk1977   return TCL_OK;
659cd03724cSdanielk1977 }
660cd03724cSdanielk1977 
6610e6f1546Sdrh 
6620e6f1546Sdrh /*
6634a50aac5Sdrh ** Usage:    sqlite3_memdebug_settitle TITLE
6644a50aac5Sdrh **
6654a50aac5Sdrh ** Set a title string stored with each allocation.  The TITLE is
6664a50aac5Sdrh ** typically the name of the test that was running when the
6674a50aac5Sdrh ** allocation occurred.  The TITLE is stored with the allocation
6684a50aac5Sdrh ** and can be used to figure out which tests are leaking memory.
6694a50aac5Sdrh **
6704a50aac5Sdrh ** Each title overwrite the previous.
6714a50aac5Sdrh */
6724a50aac5Sdrh static int test_memdebug_settitle(
6734a50aac5Sdrh   void * clientData,
6744a50aac5Sdrh   Tcl_Interp *interp,
6754a50aac5Sdrh   int objc,
6764a50aac5Sdrh   Tcl_Obj *CONST objv[]
6774a50aac5Sdrh ){
6784a50aac5Sdrh   const char *zTitle;
6794a50aac5Sdrh   if( objc!=2 ){
6804a50aac5Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
6814a50aac5Sdrh     return TCL_ERROR;
6824a50aac5Sdrh   }
6834a50aac5Sdrh   zTitle = Tcl_GetString(objv[1]);
6844a50aac5Sdrh #ifdef SQLITE_MEMDEBUG
6854a50aac5Sdrh   {
68649e4fd71Sdrh     extern int sqlite3MemdebugSettitle(const char*);
68749e4fd71Sdrh     sqlite3MemdebugSettitle(zTitle);
6884a50aac5Sdrh   }
6894a50aac5Sdrh #endif
6904a50aac5Sdrh   return TCL_OK;
6914a50aac5Sdrh }
6924a50aac5Sdrh 
693cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES 10
6946f332c18Sdanielk1977 static Tcl_HashTable aMallocLog;
6956f332c18Sdanielk1977 static int mallocLogEnabled = 0;
6966f332c18Sdanielk1977 
6976f332c18Sdanielk1977 typedef struct MallocLog MallocLog;
6986f332c18Sdanielk1977 struct MallocLog {
6996f332c18Sdanielk1977   int nCall;
7006f332c18Sdanielk1977   int nByte;
7016f332c18Sdanielk1977 };
7026f332c18Sdanielk1977 
703afdd23a4Sshane #ifdef SQLITE_MEMDEBUG
7046f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
7056f332c18Sdanielk1977   if( mallocLogEnabled ){
7066f332c18Sdanielk1977     MallocLog *pLog;
7076f332c18Sdanielk1977     Tcl_HashEntry *pEntry;
7086f332c18Sdanielk1977     int isNew;
7096f332c18Sdanielk1977 
7106f332c18Sdanielk1977     int aKey[MALLOC_LOG_FRAMES];
7116f332c18Sdanielk1977     int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
7126f332c18Sdanielk1977 
7136f332c18Sdanielk1977     memset(aKey, 0, nKey);
7146f332c18Sdanielk1977     if( (sizeof(void*)*nFrame)<nKey ){
7156f332c18Sdanielk1977       nKey = nFrame*sizeof(void*);
7166f332c18Sdanielk1977     }
7176f332c18Sdanielk1977     memcpy(aKey, aFrame, nKey);
7186f332c18Sdanielk1977 
7196f332c18Sdanielk1977     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
7206f332c18Sdanielk1977     if( isNew ){
7216f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
7226f332c18Sdanielk1977       memset(pLog, 0, sizeof(MallocLog));
7236f332c18Sdanielk1977       Tcl_SetHashValue(pEntry, (ClientData)pLog);
7246f332c18Sdanielk1977     }else{
7256f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
7266f332c18Sdanielk1977     }
7276f332c18Sdanielk1977 
7286f332c18Sdanielk1977     pLog->nCall++;
7296f332c18Sdanielk1977     pLog->nByte += nByte;
7306f332c18Sdanielk1977   }
7316f332c18Sdanielk1977 }
732afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */
7336f332c18Sdanielk1977 
7345f096135Sdanielk1977 static void test_memdebug_log_clear(){
735dbdc4d49Sdanielk1977   Tcl_HashSearch search;
736dbdc4d49Sdanielk1977   Tcl_HashEntry *pEntry;
737dbdc4d49Sdanielk1977   for(
738dbdc4d49Sdanielk1977     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
739dbdc4d49Sdanielk1977     pEntry;
740dbdc4d49Sdanielk1977     pEntry=Tcl_NextHashEntry(&search)
741dbdc4d49Sdanielk1977   ){
742dbdc4d49Sdanielk1977     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
743dbdc4d49Sdanielk1977     Tcl_Free((char *)pLog);
744dbdc4d49Sdanielk1977   }
745dbdc4d49Sdanielk1977   Tcl_DeleteHashTable(&aMallocLog);
746dbdc4d49Sdanielk1977   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
747dbdc4d49Sdanielk1977 }
748dbdc4d49Sdanielk1977 
7496f332c18Sdanielk1977 static int test_memdebug_log(
7506f332c18Sdanielk1977   void * clientData,
7516f332c18Sdanielk1977   Tcl_Interp *interp,
7526f332c18Sdanielk1977   int objc,
7536f332c18Sdanielk1977   Tcl_Obj *CONST objv[]
7546f332c18Sdanielk1977 ){
7556f332c18Sdanielk1977   static int isInit = 0;
7566f332c18Sdanielk1977   int iSub;
7576f332c18Sdanielk1977 
758dbdc4d49Sdanielk1977   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
759dbdc4d49Sdanielk1977   enum MB_enum {
760dbdc4d49Sdanielk1977       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
761dbdc4d49Sdanielk1977   };
7626f332c18Sdanielk1977 
7636f332c18Sdanielk1977   if( !isInit ){
7646f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG
7656f332c18Sdanielk1977     extern void sqlite3MemdebugBacktraceCallback(
7666f332c18Sdanielk1977         void (*xBacktrace)(int, int, void **));
7676f332c18Sdanielk1977     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
7686f332c18Sdanielk1977 #endif
7696f332c18Sdanielk1977     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
7706f332c18Sdanielk1977     isInit = 1;
7716f332c18Sdanielk1977   }
7726f332c18Sdanielk1977 
7736f332c18Sdanielk1977   if( objc<2 ){
7746f332c18Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
7756f332c18Sdanielk1977   }
7766f332c18Sdanielk1977   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
7776f332c18Sdanielk1977     return TCL_ERROR;
7786f332c18Sdanielk1977   }
7796f332c18Sdanielk1977 
7806f332c18Sdanielk1977   switch( (enum MB_enum)iSub ){
7816f332c18Sdanielk1977     case MB_LOG_START:
7826f332c18Sdanielk1977       mallocLogEnabled = 1;
7836f332c18Sdanielk1977       break;
7846f332c18Sdanielk1977     case MB_LOG_STOP:
7856f332c18Sdanielk1977       mallocLogEnabled = 0;
7866f332c18Sdanielk1977       break;
7876f332c18Sdanielk1977     case MB_LOG_DUMP: {
7886f332c18Sdanielk1977       Tcl_HashSearch search;
7896f332c18Sdanielk1977       Tcl_HashEntry *pEntry;
7906f332c18Sdanielk1977       Tcl_Obj *pRet = Tcl_NewObj();
7916f332c18Sdanielk1977 
7926f332c18Sdanielk1977       assert(sizeof(int)==sizeof(void*));
7936f332c18Sdanielk1977 
7946f332c18Sdanielk1977       for(
7956f332c18Sdanielk1977         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
7966f332c18Sdanielk1977         pEntry;
7976f332c18Sdanielk1977         pEntry=Tcl_NextHashEntry(&search)
7986f332c18Sdanielk1977       ){
7996f332c18Sdanielk1977         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
8006f332c18Sdanielk1977         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
8016f332c18Sdanielk1977         int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
8026f332c18Sdanielk1977         int ii;
8036f332c18Sdanielk1977 
8046f332c18Sdanielk1977         apElem[0] = Tcl_NewIntObj(pLog->nCall);
8056f332c18Sdanielk1977         apElem[1] = Tcl_NewIntObj(pLog->nByte);
8066f332c18Sdanielk1977         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
8076f332c18Sdanielk1977           apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
8086f332c18Sdanielk1977         }
8096f332c18Sdanielk1977 
8106f332c18Sdanielk1977         Tcl_ListObjAppendElement(interp, pRet,
8116f332c18Sdanielk1977             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
8126f332c18Sdanielk1977         );
8136f332c18Sdanielk1977       }
8146f332c18Sdanielk1977 
8156f332c18Sdanielk1977       Tcl_SetObjResult(interp, pRet);
8166f332c18Sdanielk1977       break;
8176f332c18Sdanielk1977     }
8186f332c18Sdanielk1977     case MB_LOG_CLEAR: {
819dbdc4d49Sdanielk1977       test_memdebug_log_clear();
820dbdc4d49Sdanielk1977       break;
8216f332c18Sdanielk1977     }
822dbdc4d49Sdanielk1977 
823dbdc4d49Sdanielk1977     case MB_LOG_SYNC: {
824b940492eSdrh #ifdef SQLITE_MEMDEBUG
825dbdc4d49Sdanielk1977       extern void sqlite3MemdebugSync();
826dbdc4d49Sdanielk1977       test_memdebug_log_clear();
827dbdc4d49Sdanielk1977       mallocLogEnabled = 1;
828dbdc4d49Sdanielk1977       sqlite3MemdebugSync();
829b940492eSdrh #endif
830dbdc4d49Sdanielk1977       break;
8316f332c18Sdanielk1977     }
8326f332c18Sdanielk1977   }
8336f332c18Sdanielk1977 
8346f332c18Sdanielk1977   return TCL_OK;
8356f332c18Sdanielk1977 }
8364a50aac5Sdrh 
8374a50aac5Sdrh /*
8389ac3fe97Sdrh ** Usage:    sqlite3_config_scratch SIZE N
8399ac3fe97Sdrh **
8409ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
8419ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
8429ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size.
8439ac3fe97Sdrh ** The revised value of N is returned.
8449ac3fe97Sdrh **
8459ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
8469ac3fe97Sdrh */
8479ac3fe97Sdrh static int test_config_scratch(
8489ac3fe97Sdrh   void * clientData,
8499ac3fe97Sdrh   Tcl_Interp *interp,
8509ac3fe97Sdrh   int objc,
8519ac3fe97Sdrh   Tcl_Obj *CONST objv[]
8529ac3fe97Sdrh ){
8539ac3fe97Sdrh   int sz, N, rc;
8549ac3fe97Sdrh   Tcl_Obj *pResult;
855f7141990Sdrh   static char buf[30000];
8569ac3fe97Sdrh   if( objc!=3 ){
8579ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
8589ac3fe97Sdrh     return TCL_ERROR;
8599ac3fe97Sdrh   }
860f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
861f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
8629ac3fe97Sdrh   if( sz<0 ){
8639ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
864f7141990Sdrh   }else{
8659ac3fe97Sdrh     int mx = sizeof(buf)/(sz+4);
8669ac3fe97Sdrh     if( N>mx ) N = mx;
8679ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
8689ac3fe97Sdrh   }
8699ac3fe97Sdrh   pResult = Tcl_NewObj();
8709ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
8719ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
8729ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
8739ac3fe97Sdrh   return TCL_OK;
8749ac3fe97Sdrh }
8759ac3fe97Sdrh 
8769ac3fe97Sdrh /*
8779ac3fe97Sdrh ** Usage:    sqlite3_config_pagecache SIZE N
8789ac3fe97Sdrh **
8799ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
8809ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
8819ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size.
8829ac3fe97Sdrh ** The revised value of N is returned.
8839ac3fe97Sdrh **
8849ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
8859ac3fe97Sdrh */
8869ac3fe97Sdrh static int test_config_pagecache(
8879ac3fe97Sdrh   void * clientData,
8889ac3fe97Sdrh   Tcl_Interp *interp,
8899ac3fe97Sdrh   int objc,
8909ac3fe97Sdrh   Tcl_Obj *CONST objv[]
8919ac3fe97Sdrh ){
8929ac3fe97Sdrh   int sz, N, rc;
8939ac3fe97Sdrh   Tcl_Obj *pResult;
8949ac3fe97Sdrh   static char buf[100000];
8959ac3fe97Sdrh   if( objc!=3 ){
8969ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
8979ac3fe97Sdrh     return TCL_ERROR;
8989ac3fe97Sdrh   }
899f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
900f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
9019ac3fe97Sdrh   if( sz<0 ){
902f7141990Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
903f7141990Sdrh   }else{
9049ac3fe97Sdrh     int mx = sizeof(buf)/(sz+4);
9059ac3fe97Sdrh     if( N>mx ) N = mx;
9069ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
9079ac3fe97Sdrh   }
9089ac3fe97Sdrh   pResult = Tcl_NewObj();
9099ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
9109ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
9119ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
9129ac3fe97Sdrh   return TCL_OK;
9139ac3fe97Sdrh }
9149ac3fe97Sdrh 
915f7141990Sdrh /*
916f7141990Sdrh ** Usage:    sqlite3_status  OPCODE  RESETFLAG
917f7141990Sdrh **
918f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return
919f7141990Sdrh ** code, the current value, and the high-water mark value.
920f7141990Sdrh */
921f7141990Sdrh static int test_status(
922f7141990Sdrh   void * clientData,
923f7141990Sdrh   Tcl_Interp *interp,
924f7141990Sdrh   int objc,
925f7141990Sdrh   Tcl_Obj *CONST objv[]
926f7141990Sdrh ){
927f7141990Sdrh   int rc, iValue, mxValue;
928f7141990Sdrh   int i, op, resetFlag;
929f7141990Sdrh   const char *zOpName;
930f7141990Sdrh   static const struct {
931f7141990Sdrh     const char *zName;
932f7141990Sdrh     int op;
933f7141990Sdrh   } aOp[] = {
934f7141990Sdrh     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
935f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
936f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
937f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
938f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
939f7141990Sdrh     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
940f7141990Sdrh   };
941f7141990Sdrh   Tcl_Obj *pResult;
942f7141990Sdrh   if( objc!=3 ){
943f7141990Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
944f7141990Sdrh     return TCL_ERROR;
945f7141990Sdrh   }
946f7141990Sdrh   zOpName = Tcl_GetString(objv[1]);
947f7141990Sdrh   for(i=0; i<ArraySize(aOp); i++){
948f7141990Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
949f7141990Sdrh       op = aOp[i].op;
950f7141990Sdrh       break;
951f7141990Sdrh     }
952f7141990Sdrh   }
953f7141990Sdrh   if( i>=ArraySize(aOp) ){
954f7141990Sdrh     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
955f7141990Sdrh   }
956f7141990Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
957f7141990Sdrh   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
958f7141990Sdrh   pResult = Tcl_NewObj();
959f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
960f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
961f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
962f7141990Sdrh   Tcl_SetObjResult(interp, pResult);
963f7141990Sdrh   return TCL_OK;
964f7141990Sdrh }
9659ac3fe97Sdrh 
9669ac3fe97Sdrh /*
967d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN
968d09414cdSdanielk1977 */
969d09414cdSdanielk1977 static int test_install_malloc_faultsim(
970d09414cdSdanielk1977   void * clientData,
971d09414cdSdanielk1977   Tcl_Interp *interp,
972d09414cdSdanielk1977   int objc,
973d09414cdSdanielk1977   Tcl_Obj *CONST objv[]
974d09414cdSdanielk1977 ){
975d09414cdSdanielk1977   int rc;
976d09414cdSdanielk1977   int isInstall;
977d09414cdSdanielk1977 
978d09414cdSdanielk1977   if( objc!=2 ){
979d09414cdSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
980d09414cdSdanielk1977     return TCL_ERROR;
981d09414cdSdanielk1977   }
982d09414cdSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
983d09414cdSdanielk1977     return TCL_ERROR;
984d09414cdSdanielk1977   }
985*ef05f2dfSdanielk1977   rc = faultsimInstall(isInstall);
986d09414cdSdanielk1977   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
987d09414cdSdanielk1977   return TCL_OK;
988d09414cdSdanielk1977 }
989d09414cdSdanielk1977 
990d09414cdSdanielk1977 /*
9912f999a67Sdrh ** Register commands with the TCL interpreter.
9922f999a67Sdrh */
9932f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){
9942f999a67Sdrh   static struct {
9952f999a67Sdrh      char *zName;
9962f999a67Sdrh      Tcl_ObjCmdProc *xProc;
9972f999a67Sdrh   } aObjCmd[] = {
9982f999a67Sdrh      { "sqlite3_malloc",             test_malloc                   },
9992f999a67Sdrh      { "sqlite3_realloc",            test_realloc                  },
10002f999a67Sdrh      { "sqlite3_free",               test_free                     },
10019c7a60dfSdrh      { "memset",                     test_memset                   },
10029c7a60dfSdrh      { "memget",                     test_memget                   },
10032f999a67Sdrh      { "sqlite3_memory_used",        test_memory_used              },
10042f999a67Sdrh      { "sqlite3_memory_highwater",   test_memory_highwater         },
10052f999a67Sdrh      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       },
10062f999a67Sdrh      { "sqlite3_memdebug_dump",      test_memdebug_dump            },
10070e6f1546Sdrh      { "sqlite3_memdebug_fail",      test_memdebug_fail            },
1008cd03724cSdanielk1977      { "sqlite3_memdebug_pending",   test_memdebug_pending         },
10094a50aac5Sdrh      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        },
1010a7a8e14bSdanielk1977      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
10116f332c18Sdanielk1977      { "sqlite3_memdebug_log",       test_memdebug_log             },
10129ac3fe97Sdrh      { "sqlite3_config_scratch",     test_config_scratch           },
10139ac3fe97Sdrh      { "sqlite3_config_pagecache",   test_config_pagecache         },
1014f7141990Sdrh      { "sqlite3_status",             test_status                   },
1015d09414cdSdanielk1977 
1016d09414cdSdanielk1977      { "install_malloc_faultsim",    test_install_malloc_faultsim  },
10172f999a67Sdrh   };
10182f999a67Sdrh   int i;
10192f999a67Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
10202f999a67Sdrh     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
10212f999a67Sdrh   }
10222f999a67Sdrh   return TCL_OK;
10232f999a67Sdrh }
1024*ef05f2dfSdanielk1977 #endif
1025