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