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*af005fbcSdrh ** $Id: test_malloc.c,v 1.35 2008/07/09 16:51:51 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{ 2072d1d86fbSdanielk1977 assert(memfault.m.xMalloc); 2082d1d86fbSdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m); 2092d1d86fbSdanielk1977 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0); 2102d1d86fbSdanielk1977 } 211ef05f2dfSdanielk1977 212ef05f2dfSdanielk1977 if( rc==SQLITE_OK ){ 213ef05f2dfSdanielk1977 memfault.isInstalled = 1; 214ef05f2dfSdanielk1977 } 215ef05f2dfSdanielk1977 return rc; 216ef05f2dfSdanielk1977 } 217ef05f2dfSdanielk1977 218ef05f2dfSdanielk1977 #ifdef SQLITE_TEST 219ef05f2dfSdanielk1977 220ef05f2dfSdanielk1977 /* 221ef05f2dfSdanielk1977 ** This function is implemented in test1.c. Returns a pointer to a static 222ef05f2dfSdanielk1977 ** buffer containing the symbolic SQLite error code that corresponds to 223ef05f2dfSdanielk1977 ** the least-significant 8-bits of the integer passed as an argument. 224ef05f2dfSdanielk1977 ** For example: 225ef05f2dfSdanielk1977 ** 226ef05f2dfSdanielk1977 ** sqlite3TestErrorName(1) -> "SQLITE_ERROR" 227ef05f2dfSdanielk1977 */ 228d09414cdSdanielk1977 const char *sqlite3TestErrorName(int); 229d09414cdSdanielk1977 2302f999a67Sdrh /* 2312f999a67Sdrh ** Transform pointers to text and back again 2322f999a67Sdrh */ 2332f999a67Sdrh static void pointerToText(void *p, char *z){ 2342f999a67Sdrh static const char zHex[] = "0123456789abcdef"; 2352f999a67Sdrh int i, k; 2364a50aac5Sdrh unsigned int u; 2374a50aac5Sdrh sqlite3_uint64 n; 2384a50aac5Sdrh if( sizeof(n)==sizeof(p) ){ 2394a50aac5Sdrh memcpy(&n, &p, sizeof(p)); 2404a50aac5Sdrh }else if( sizeof(u)==sizeof(p) ){ 2414a50aac5Sdrh memcpy(&u, &p, sizeof(u)); 2424a50aac5Sdrh n = u; 2434a50aac5Sdrh }else{ 2444a50aac5Sdrh assert( 0 ); 2454a50aac5Sdrh } 2462f999a67Sdrh for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 2472f999a67Sdrh z[k] = zHex[n&0xf]; 2482f999a67Sdrh n >>= 4; 2492f999a67Sdrh } 2502f999a67Sdrh z[sizeof(p)*2] = 0; 2512f999a67Sdrh } 2522f999a67Sdrh static int hexToInt(int h){ 2532f999a67Sdrh if( h>='0' && h<='9' ){ 2542f999a67Sdrh return h - '0'; 2552f999a67Sdrh }else if( h>='a' && h<='f' ){ 2562f999a67Sdrh return h - 'a' + 10; 2572f999a67Sdrh }else{ 2582f999a67Sdrh return -1; 2592f999a67Sdrh } 2602f999a67Sdrh } 2612f999a67Sdrh static int textToPointer(const char *z, void **pp){ 2622f999a67Sdrh sqlite3_uint64 n = 0; 2632f999a67Sdrh int i; 2644a50aac5Sdrh unsigned int u; 2652f999a67Sdrh for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 2662f999a67Sdrh int v; 2672f999a67Sdrh v = hexToInt(*z++); 2682f999a67Sdrh if( v<0 ) return TCL_ERROR; 2692f999a67Sdrh n = n*16 + v; 2702f999a67Sdrh } 2712f999a67Sdrh if( *z!=0 ) return TCL_ERROR; 2724a50aac5Sdrh if( sizeof(n)==sizeof(*pp) ){ 2734a50aac5Sdrh memcpy(pp, &n, sizeof(n)); 2744a50aac5Sdrh }else if( sizeof(u)==sizeof(*pp) ){ 2754a50aac5Sdrh u = (unsigned int)n; 2764a50aac5Sdrh memcpy(pp, &u, sizeof(u)); 2774a50aac5Sdrh }else{ 2784a50aac5Sdrh assert( 0 ); 2794a50aac5Sdrh } 2802f999a67Sdrh return TCL_OK; 2812f999a67Sdrh } 2822f999a67Sdrh 2832f999a67Sdrh /* 2842f999a67Sdrh ** Usage: sqlite3_malloc NBYTES 2852f999a67Sdrh ** 2862f999a67Sdrh ** Raw test interface for sqlite3_malloc(). 2872f999a67Sdrh */ 2882f999a67Sdrh static int test_malloc( 2892f999a67Sdrh void * clientData, 2902f999a67Sdrh Tcl_Interp *interp, 2912f999a67Sdrh int objc, 2922f999a67Sdrh Tcl_Obj *CONST objv[] 2932f999a67Sdrh ){ 2942f999a67Sdrh int nByte; 2952f999a67Sdrh void *p; 2962f999a67Sdrh char zOut[100]; 2972f999a67Sdrh if( objc!=2 ){ 2982f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 2992f999a67Sdrh return TCL_ERROR; 3002f999a67Sdrh } 3012f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 3022f999a67Sdrh p = sqlite3_malloc((unsigned)nByte); 3032f999a67Sdrh pointerToText(p, zOut); 3042f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 3052f999a67Sdrh return TCL_OK; 3062f999a67Sdrh } 3072f999a67Sdrh 3082f999a67Sdrh /* 3092f999a67Sdrh ** Usage: sqlite3_realloc PRIOR NBYTES 3102f999a67Sdrh ** 3112f999a67Sdrh ** Raw test interface for sqlite3_realloc(). 3122f999a67Sdrh */ 3132f999a67Sdrh static int test_realloc( 3142f999a67Sdrh void * clientData, 3152f999a67Sdrh Tcl_Interp *interp, 3162f999a67Sdrh int objc, 3172f999a67Sdrh Tcl_Obj *CONST objv[] 3182f999a67Sdrh ){ 3192f999a67Sdrh int nByte; 3202f999a67Sdrh void *pPrior, *p; 3212f999a67Sdrh char zOut[100]; 3222f999a67Sdrh if( objc!=3 ){ 3232f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 3242f999a67Sdrh return TCL_ERROR; 3252f999a67Sdrh } 3262f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 3272f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 3282f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 3292f999a67Sdrh return TCL_ERROR; 3302f999a67Sdrh } 3312f999a67Sdrh p = sqlite3_realloc(pPrior, (unsigned)nByte); 3322f999a67Sdrh pointerToText(p, zOut); 3332f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 3342f999a67Sdrh return TCL_OK; 3352f999a67Sdrh } 3362f999a67Sdrh 3372f999a67Sdrh /* 3382f999a67Sdrh ** Usage: sqlite3_free PRIOR 3392f999a67Sdrh ** 3402f999a67Sdrh ** Raw test interface for sqlite3_free(). 3412f999a67Sdrh */ 3422f999a67Sdrh static int test_free( 3432f999a67Sdrh void * clientData, 3442f999a67Sdrh Tcl_Interp *interp, 3452f999a67Sdrh int objc, 3462f999a67Sdrh Tcl_Obj *CONST objv[] 3472f999a67Sdrh ){ 3482f999a67Sdrh void *pPrior; 3492f999a67Sdrh if( objc!=2 ){ 3502f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 3512f999a67Sdrh return TCL_ERROR; 3522f999a67Sdrh } 3532f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 3542f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 3552f999a67Sdrh return TCL_ERROR; 3562f999a67Sdrh } 3572f999a67Sdrh sqlite3_free(pPrior); 3582f999a67Sdrh return TCL_OK; 3592f999a67Sdrh } 3602f999a67Sdrh 3612f999a67Sdrh /* 3629c7a60dfSdrh ** These routines are in test_hexio.c 3639c7a60dfSdrh */ 3649c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *); 3659c7a60dfSdrh int sqlite3TestBinToHex(char*,int); 3669c7a60dfSdrh 3679c7a60dfSdrh /* 3689c7a60dfSdrh ** Usage: memset ADDRESS SIZE HEX 3699c7a60dfSdrh ** 3709c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a 3719c7a60dfSdrh ** specified hex pattern. 3729c7a60dfSdrh */ 3739c7a60dfSdrh static int test_memset( 3749c7a60dfSdrh void * clientData, 3759c7a60dfSdrh Tcl_Interp *interp, 3769c7a60dfSdrh int objc, 3779c7a60dfSdrh Tcl_Obj *CONST objv[] 3789c7a60dfSdrh ){ 3799c7a60dfSdrh void *p; 3809c7a60dfSdrh int size, n, i; 3819c7a60dfSdrh char *zHex; 3829c7a60dfSdrh char *zOut; 3839c7a60dfSdrh char zBin[100]; 3849c7a60dfSdrh 3859c7a60dfSdrh if( objc!=4 ){ 3869c7a60dfSdrh Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX"); 3879c7a60dfSdrh return TCL_ERROR; 3889c7a60dfSdrh } 3899c7a60dfSdrh if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 3909c7a60dfSdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 3919c7a60dfSdrh return TCL_ERROR; 3929c7a60dfSdrh } 3939c7a60dfSdrh if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 3949c7a60dfSdrh return TCL_ERROR; 3959c7a60dfSdrh } 3969c7a60dfSdrh if( size<=0 ){ 3979c7a60dfSdrh Tcl_AppendResult(interp, "size must be positive", (char*)0); 3989c7a60dfSdrh return TCL_ERROR; 3999c7a60dfSdrh } 4009c7a60dfSdrh zHex = Tcl_GetStringFromObj(objv[3], &n); 4019c7a60dfSdrh if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2; 4029c7a60dfSdrh n = sqlite3TestHexToBin(zHex, n, zBin); 4039c7a60dfSdrh if( n==0 ){ 4049c7a60dfSdrh Tcl_AppendResult(interp, "no data", (char*)0); 4059c7a60dfSdrh return TCL_ERROR; 4069c7a60dfSdrh } 4079c7a60dfSdrh zOut = p; 4089c7a60dfSdrh for(i=0; i<size; i++){ 4099c7a60dfSdrh zOut[i] = zBin[i%n]; 4109c7a60dfSdrh } 4119c7a60dfSdrh return TCL_OK; 4129c7a60dfSdrh } 4139c7a60dfSdrh 4149c7a60dfSdrh /* 4159c7a60dfSdrh ** Usage: memget ADDRESS SIZE 4169c7a60dfSdrh ** 4179c7a60dfSdrh ** Return memory as hexadecimal text. 4189c7a60dfSdrh */ 4199c7a60dfSdrh static int test_memget( 4209c7a60dfSdrh void * clientData, 4219c7a60dfSdrh Tcl_Interp *interp, 4229c7a60dfSdrh int objc, 4239c7a60dfSdrh Tcl_Obj *CONST objv[] 4249c7a60dfSdrh ){ 4259c7a60dfSdrh void *p; 4269c7a60dfSdrh int size, n; 4279c7a60dfSdrh char *zBin; 4289c7a60dfSdrh char zHex[100]; 4299c7a60dfSdrh 4309c7a60dfSdrh if( objc!=3 ){ 4319c7a60dfSdrh Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE"); 4329c7a60dfSdrh return TCL_ERROR; 4339c7a60dfSdrh } 4349c7a60dfSdrh if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 4359c7a60dfSdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 4369c7a60dfSdrh return TCL_ERROR; 4379c7a60dfSdrh } 4389c7a60dfSdrh if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 4399c7a60dfSdrh return TCL_ERROR; 4409c7a60dfSdrh } 4419c7a60dfSdrh if( size<=0 ){ 4429c7a60dfSdrh Tcl_AppendResult(interp, "size must be positive", (char*)0); 4439c7a60dfSdrh return TCL_ERROR; 4449c7a60dfSdrh } 4459c7a60dfSdrh zBin = p; 4469c7a60dfSdrh while( size>0 ){ 4479c7a60dfSdrh if( size>(sizeof(zHex)-1)/2 ){ 4489c7a60dfSdrh n = (sizeof(zHex)-1)/2; 4499c7a60dfSdrh }else{ 4509c7a60dfSdrh n = size; 4519c7a60dfSdrh } 4529c7a60dfSdrh memcpy(zHex, zBin, n); 4539c7a60dfSdrh zBin += n; 4549c7a60dfSdrh size -= n; 4559c7a60dfSdrh sqlite3TestBinToHex(zHex, n); 4569c7a60dfSdrh Tcl_AppendResult(interp, zHex, (char*)0); 4579c7a60dfSdrh } 4589c7a60dfSdrh return TCL_OK; 4599c7a60dfSdrh } 4609c7a60dfSdrh 4619c7a60dfSdrh /* 4622f999a67Sdrh ** Usage: sqlite3_memory_used 4632f999a67Sdrh ** 4642f999a67Sdrh ** Raw test interface for sqlite3_memory_used(). 4652f999a67Sdrh */ 4662f999a67Sdrh static int test_memory_used( 4672f999a67Sdrh void * clientData, 4682f999a67Sdrh Tcl_Interp *interp, 4692f999a67Sdrh int objc, 4702f999a67Sdrh Tcl_Obj *CONST objv[] 4712f999a67Sdrh ){ 4722f999a67Sdrh Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 4732f999a67Sdrh return TCL_OK; 4742f999a67Sdrh } 4752f999a67Sdrh 4762f999a67Sdrh /* 4772f999a67Sdrh ** Usage: sqlite3_memory_highwater ?RESETFLAG? 4782f999a67Sdrh ** 4792f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater(). 4802f999a67Sdrh */ 4812f999a67Sdrh static int test_memory_highwater( 4822f999a67Sdrh void * clientData, 4832f999a67Sdrh Tcl_Interp *interp, 4842f999a67Sdrh int objc, 4852f999a67Sdrh Tcl_Obj *CONST objv[] 4862f999a67Sdrh ){ 4872f999a67Sdrh int resetFlag = 0; 4882f999a67Sdrh if( objc!=1 && objc!=2 ){ 4892f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 4902f999a67Sdrh return TCL_ERROR; 4912f999a67Sdrh } 4922f999a67Sdrh if( objc==2 ){ 4932f999a67Sdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 4942f999a67Sdrh } 4952f999a67Sdrh Tcl_SetObjResult(interp, 4962f999a67Sdrh Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 4972f999a67Sdrh return TCL_OK; 4982f999a67Sdrh } 4992f999a67Sdrh 5002f999a67Sdrh /* 5012f999a67Sdrh ** Usage: sqlite3_memdebug_backtrace DEPTH 5022f999a67Sdrh ** 5032f999a67Sdrh ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 5042f999a67Sdrh ** then this routine is a no-op. 5052f999a67Sdrh */ 5062f999a67Sdrh static int test_memdebug_backtrace( 5072f999a67Sdrh void * clientData, 5082f999a67Sdrh Tcl_Interp *interp, 5092f999a67Sdrh int objc, 5102f999a67Sdrh Tcl_Obj *CONST objv[] 5112f999a67Sdrh ){ 5122f999a67Sdrh int depth; 5132f999a67Sdrh if( objc!=2 ){ 5142f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 5152f999a67Sdrh return TCL_ERROR; 5162f999a67Sdrh } 5172f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 5182f999a67Sdrh #ifdef SQLITE_MEMDEBUG 5192f999a67Sdrh { 52049e4fd71Sdrh extern void sqlite3MemdebugBacktrace(int); 52149e4fd71Sdrh sqlite3MemdebugBacktrace(depth); 5222f999a67Sdrh } 5232f999a67Sdrh #endif 5242f999a67Sdrh return TCL_OK; 5252f999a67Sdrh } 5262f999a67Sdrh 5272f999a67Sdrh /* 5282f999a67Sdrh ** Usage: sqlite3_memdebug_dump FILENAME 5292f999a67Sdrh ** 5302f999a67Sdrh ** Write a summary of unfreed memory to FILENAME. 5312f999a67Sdrh */ 5322f999a67Sdrh static int test_memdebug_dump( 5332f999a67Sdrh void * clientData, 5342f999a67Sdrh Tcl_Interp *interp, 5352f999a67Sdrh int objc, 5362f999a67Sdrh Tcl_Obj *CONST objv[] 5372f999a67Sdrh ){ 5382f999a67Sdrh if( objc!=2 ){ 5392f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 5402f999a67Sdrh return TCL_ERROR; 5412f999a67Sdrh } 5422d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ 5432d7636e2Sdrh || defined(SQLITE_POW2_MEMORY_SIZE) 5442f999a67Sdrh { 54549e4fd71Sdrh extern void sqlite3MemdebugDump(const char*); 54649e4fd71Sdrh sqlite3MemdebugDump(Tcl_GetString(objv[1])); 5472f999a67Sdrh } 5482f999a67Sdrh #endif 5492f999a67Sdrh return TCL_OK; 5502f999a67Sdrh } 5512f999a67Sdrh 552a7a8e14bSdanielk1977 /* 553a7a8e14bSdanielk1977 ** Usage: sqlite3_memdebug_malloc_count 554a7a8e14bSdanielk1977 ** 555a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called. 556a7a8e14bSdanielk1977 */ 557a7a8e14bSdanielk1977 static int test_memdebug_malloc_count( 558a7a8e14bSdanielk1977 void * clientData, 559a7a8e14bSdanielk1977 Tcl_Interp *interp, 560a7a8e14bSdanielk1977 int objc, 561a7a8e14bSdanielk1977 Tcl_Obj *CONST objv[] 562a7a8e14bSdanielk1977 ){ 563a7a8e14bSdanielk1977 int nMalloc = -1; 564a7a8e14bSdanielk1977 if( objc!=1 ){ 565a7a8e14bSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, ""); 566a7a8e14bSdanielk1977 return TCL_ERROR; 567a7a8e14bSdanielk1977 } 568a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG) 569a7a8e14bSdanielk1977 { 57049e4fd71Sdrh extern int sqlite3MemdebugMallocCount(); 57149e4fd71Sdrh nMalloc = sqlite3MemdebugMallocCount(); 572a7a8e14bSdanielk1977 } 573a7a8e14bSdanielk1977 #endif 574a7a8e14bSdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); 575a7a8e14bSdanielk1977 return TCL_OK; 576a7a8e14bSdanielk1977 } 577a7a8e14bSdanielk1977 5782f999a67Sdrh 5792f999a67Sdrh /* 580a1644fd8Sdanielk1977 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? 581a1644fd8Sdanielk1977 ** 582a1644fd8Sdanielk1977 ** where options are: 583a1644fd8Sdanielk1977 ** 584643167ffSdrh ** -repeat <count> 585a1644fd8Sdanielk1977 ** -benigncnt <varname> 5860e6f1546Sdrh ** 5870e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes. 588643167ffSdrh ** If a repeat count is specified, the fault is repeated that many 589643167ffSdrh ** times. 5900e6f1546Sdrh ** 5910e6f1546Sdrh ** Each call to this routine overrides the prior counter value. 5920e6f1546Sdrh ** This routine returns the number of simulated failures that have 5930e6f1546Sdrh ** happened since the previous call to this routine. 5940e6f1546Sdrh ** 5950e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1. 5960e6f1546Sdrh */ 5970e6f1546Sdrh static int test_memdebug_fail( 5980e6f1546Sdrh void * clientData, 5990e6f1546Sdrh Tcl_Interp *interp, 6000e6f1546Sdrh int objc, 6010e6f1546Sdrh Tcl_Obj *CONST objv[] 6020e6f1546Sdrh ){ 603a1644fd8Sdanielk1977 int ii; 6040e6f1546Sdrh int iFail; 605643167ffSdrh int nRepeat = 1; 606a1644fd8Sdanielk1977 Tcl_Obj *pBenignCnt = 0; 607643167ffSdrh int nBenign; 6080e6f1546Sdrh int nFail = 0; 609a1644fd8Sdanielk1977 610a1644fd8Sdanielk1977 if( objc<2 ){ 611a1644fd8Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); 6120e6f1546Sdrh return TCL_ERROR; 6130e6f1546Sdrh } 6140e6f1546Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 615a1644fd8Sdanielk1977 616a1644fd8Sdanielk1977 for(ii=2; ii<objc; ii+=2){ 617a1644fd8Sdanielk1977 int nOption; 618a1644fd8Sdanielk1977 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); 619a1644fd8Sdanielk1977 char *zErr = 0; 620a1644fd8Sdanielk1977 621a1644fd8Sdanielk1977 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ 622a1644fd8Sdanielk1977 if( ii==(objc-1) ){ 623a1644fd8Sdanielk1977 zErr = "option requires an argument: "; 624ed138fb3Sdrh }else{ 625643167ffSdrh if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ 626a1644fd8Sdanielk1977 return TCL_ERROR; 627ed138fb3Sdrh } 628a1644fd8Sdanielk1977 } 629a1644fd8Sdanielk1977 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ 630a1644fd8Sdanielk1977 if( ii==(objc-1) ){ 631a1644fd8Sdanielk1977 zErr = "option requires an argument: "; 632a1644fd8Sdanielk1977 }else{ 633a1644fd8Sdanielk1977 pBenignCnt = objv[ii+1]; 634a1644fd8Sdanielk1977 } 635a1644fd8Sdanielk1977 }else{ 636a1644fd8Sdanielk1977 zErr = "unknown option: "; 637a1644fd8Sdanielk1977 } 638a1644fd8Sdanielk1977 639a1644fd8Sdanielk1977 if( zErr ){ 640a1644fd8Sdanielk1977 Tcl_AppendResult(interp, zErr, zOption, 0); 641a1644fd8Sdanielk1977 return TCL_ERROR; 642a1644fd8Sdanielk1977 } 643a1644fd8Sdanielk1977 } 644a1644fd8Sdanielk1977 645ef05f2dfSdanielk1977 nBenign = faultsimBenignFailures(); 646ef05f2dfSdanielk1977 nFail = faultsimFailures(); 647ef05f2dfSdanielk1977 faultsimConfig(iFail, nRepeat); 648ef05f2dfSdanielk1977 649a1644fd8Sdanielk1977 if( pBenignCnt ){ 650643167ffSdrh Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); 651a1644fd8Sdanielk1977 } 6520e6f1546Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 6530e6f1546Sdrh return TCL_OK; 6540e6f1546Sdrh } 6550e6f1546Sdrh 656cd03724cSdanielk1977 /* 657cd03724cSdanielk1977 ** Usage: sqlite3_memdebug_pending 658cd03724cSdanielk1977 ** 659cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a 660cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that 661cd03724cSdanielk1977 ** no malloc() failure is scheduled. 662cd03724cSdanielk1977 */ 663cd03724cSdanielk1977 static int test_memdebug_pending( 664cd03724cSdanielk1977 void * clientData, 665cd03724cSdanielk1977 Tcl_Interp *interp, 666cd03724cSdanielk1977 int objc, 667cd03724cSdanielk1977 Tcl_Obj *CONST objv[] 668cd03724cSdanielk1977 ){ 6695efaf070Sdrh int nPending; 670cd03724cSdanielk1977 if( objc!=1 ){ 671cd03724cSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, ""); 672cd03724cSdanielk1977 return TCL_ERROR; 673cd03724cSdanielk1977 } 674ef05f2dfSdanielk1977 nPending = faultsimPending(); 675ed13d98cSdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending)); 676cd03724cSdanielk1977 return TCL_OK; 677cd03724cSdanielk1977 } 678cd03724cSdanielk1977 6790e6f1546Sdrh 6800e6f1546Sdrh /* 6814a50aac5Sdrh ** Usage: sqlite3_memdebug_settitle TITLE 6824a50aac5Sdrh ** 6834a50aac5Sdrh ** Set a title string stored with each allocation. The TITLE is 6844a50aac5Sdrh ** typically the name of the test that was running when the 6854a50aac5Sdrh ** allocation occurred. The TITLE is stored with the allocation 6864a50aac5Sdrh ** and can be used to figure out which tests are leaking memory. 6874a50aac5Sdrh ** 6884a50aac5Sdrh ** Each title overwrite the previous. 6894a50aac5Sdrh */ 6904a50aac5Sdrh static int test_memdebug_settitle( 6914a50aac5Sdrh void * clientData, 6924a50aac5Sdrh Tcl_Interp *interp, 6934a50aac5Sdrh int objc, 6944a50aac5Sdrh Tcl_Obj *CONST objv[] 6954a50aac5Sdrh ){ 6964a50aac5Sdrh const char *zTitle; 6974a50aac5Sdrh if( objc!=2 ){ 6984a50aac5Sdrh Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); 6994a50aac5Sdrh return TCL_ERROR; 7004a50aac5Sdrh } 7014a50aac5Sdrh zTitle = Tcl_GetString(objv[1]); 7024a50aac5Sdrh #ifdef SQLITE_MEMDEBUG 7034a50aac5Sdrh { 70449e4fd71Sdrh extern int sqlite3MemdebugSettitle(const char*); 70549e4fd71Sdrh sqlite3MemdebugSettitle(zTitle); 7064a50aac5Sdrh } 7074a50aac5Sdrh #endif 7084a50aac5Sdrh return TCL_OK; 7094a50aac5Sdrh } 7104a50aac5Sdrh 711cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES 10 7126f332c18Sdanielk1977 static Tcl_HashTable aMallocLog; 7136f332c18Sdanielk1977 static int mallocLogEnabled = 0; 7146f332c18Sdanielk1977 7156f332c18Sdanielk1977 typedef struct MallocLog MallocLog; 7166f332c18Sdanielk1977 struct MallocLog { 7176f332c18Sdanielk1977 int nCall; 7186f332c18Sdanielk1977 int nByte; 7196f332c18Sdanielk1977 }; 7206f332c18Sdanielk1977 721afdd23a4Sshane #ifdef SQLITE_MEMDEBUG 7226f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ 7236f332c18Sdanielk1977 if( mallocLogEnabled ){ 7246f332c18Sdanielk1977 MallocLog *pLog; 7256f332c18Sdanielk1977 Tcl_HashEntry *pEntry; 7266f332c18Sdanielk1977 int isNew; 7276f332c18Sdanielk1977 7286f332c18Sdanielk1977 int aKey[MALLOC_LOG_FRAMES]; 7296f332c18Sdanielk1977 int nKey = sizeof(int)*MALLOC_LOG_FRAMES; 7306f332c18Sdanielk1977 7316f332c18Sdanielk1977 memset(aKey, 0, nKey); 7326f332c18Sdanielk1977 if( (sizeof(void*)*nFrame)<nKey ){ 7336f332c18Sdanielk1977 nKey = nFrame*sizeof(void*); 7346f332c18Sdanielk1977 } 7356f332c18Sdanielk1977 memcpy(aKey, aFrame, nKey); 7366f332c18Sdanielk1977 7376f332c18Sdanielk1977 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); 7386f332c18Sdanielk1977 if( isNew ){ 7396f332c18Sdanielk1977 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); 7406f332c18Sdanielk1977 memset(pLog, 0, sizeof(MallocLog)); 7416f332c18Sdanielk1977 Tcl_SetHashValue(pEntry, (ClientData)pLog); 7426f332c18Sdanielk1977 }else{ 7436f332c18Sdanielk1977 pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 7446f332c18Sdanielk1977 } 7456f332c18Sdanielk1977 7466f332c18Sdanielk1977 pLog->nCall++; 7476f332c18Sdanielk1977 pLog->nByte += nByte; 7486f332c18Sdanielk1977 } 7496f332c18Sdanielk1977 } 750afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */ 7516f332c18Sdanielk1977 7525f096135Sdanielk1977 static void test_memdebug_log_clear(){ 753dbdc4d49Sdanielk1977 Tcl_HashSearch search; 754dbdc4d49Sdanielk1977 Tcl_HashEntry *pEntry; 755dbdc4d49Sdanielk1977 for( 756dbdc4d49Sdanielk1977 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 757dbdc4d49Sdanielk1977 pEntry; 758dbdc4d49Sdanielk1977 pEntry=Tcl_NextHashEntry(&search) 759dbdc4d49Sdanielk1977 ){ 760dbdc4d49Sdanielk1977 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 761dbdc4d49Sdanielk1977 Tcl_Free((char *)pLog); 762dbdc4d49Sdanielk1977 } 763dbdc4d49Sdanielk1977 Tcl_DeleteHashTable(&aMallocLog); 764dbdc4d49Sdanielk1977 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 765dbdc4d49Sdanielk1977 } 766dbdc4d49Sdanielk1977 7676f332c18Sdanielk1977 static int test_memdebug_log( 7686f332c18Sdanielk1977 void * clientData, 7696f332c18Sdanielk1977 Tcl_Interp *interp, 7706f332c18Sdanielk1977 int objc, 7716f332c18Sdanielk1977 Tcl_Obj *CONST objv[] 7726f332c18Sdanielk1977 ){ 7736f332c18Sdanielk1977 static int isInit = 0; 7746f332c18Sdanielk1977 int iSub; 7756f332c18Sdanielk1977 776dbdc4d49Sdanielk1977 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" }; 777dbdc4d49Sdanielk1977 enum MB_enum { 778dbdc4d49Sdanielk1977 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC 779dbdc4d49Sdanielk1977 }; 7806f332c18Sdanielk1977 7816f332c18Sdanielk1977 if( !isInit ){ 7826f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG 7836f332c18Sdanielk1977 extern void sqlite3MemdebugBacktraceCallback( 7846f332c18Sdanielk1977 void (*xBacktrace)(int, int, void **)); 7856f332c18Sdanielk1977 sqlite3MemdebugBacktraceCallback(test_memdebug_callback); 7866f332c18Sdanielk1977 #endif 7876f332c18Sdanielk1977 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 7886f332c18Sdanielk1977 isInit = 1; 7896f332c18Sdanielk1977 } 7906f332c18Sdanielk1977 7916f332c18Sdanielk1977 if( objc<2 ){ 7926f332c18Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 7936f332c18Sdanielk1977 } 7946f332c18Sdanielk1977 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ 7956f332c18Sdanielk1977 return TCL_ERROR; 7966f332c18Sdanielk1977 } 7976f332c18Sdanielk1977 7986f332c18Sdanielk1977 switch( (enum MB_enum)iSub ){ 7996f332c18Sdanielk1977 case MB_LOG_START: 8006f332c18Sdanielk1977 mallocLogEnabled = 1; 8016f332c18Sdanielk1977 break; 8026f332c18Sdanielk1977 case MB_LOG_STOP: 8036f332c18Sdanielk1977 mallocLogEnabled = 0; 8046f332c18Sdanielk1977 break; 8056f332c18Sdanielk1977 case MB_LOG_DUMP: { 8066f332c18Sdanielk1977 Tcl_HashSearch search; 8076f332c18Sdanielk1977 Tcl_HashEntry *pEntry; 8086f332c18Sdanielk1977 Tcl_Obj *pRet = Tcl_NewObj(); 8096f332c18Sdanielk1977 8106f332c18Sdanielk1977 assert(sizeof(int)==sizeof(void*)); 8116f332c18Sdanielk1977 8126f332c18Sdanielk1977 for( 8136f332c18Sdanielk1977 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 8146f332c18Sdanielk1977 pEntry; 8156f332c18Sdanielk1977 pEntry=Tcl_NextHashEntry(&search) 8166f332c18Sdanielk1977 ){ 8176f332c18Sdanielk1977 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; 8186f332c18Sdanielk1977 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 8196f332c18Sdanielk1977 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry); 8206f332c18Sdanielk1977 int ii; 8216f332c18Sdanielk1977 8226f332c18Sdanielk1977 apElem[0] = Tcl_NewIntObj(pLog->nCall); 8236f332c18Sdanielk1977 apElem[1] = Tcl_NewIntObj(pLog->nByte); 8246f332c18Sdanielk1977 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ 8256f332c18Sdanielk1977 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]); 8266f332c18Sdanielk1977 } 8276f332c18Sdanielk1977 8286f332c18Sdanielk1977 Tcl_ListObjAppendElement(interp, pRet, 8296f332c18Sdanielk1977 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) 8306f332c18Sdanielk1977 ); 8316f332c18Sdanielk1977 } 8326f332c18Sdanielk1977 8336f332c18Sdanielk1977 Tcl_SetObjResult(interp, pRet); 8346f332c18Sdanielk1977 break; 8356f332c18Sdanielk1977 } 8366f332c18Sdanielk1977 case MB_LOG_CLEAR: { 837dbdc4d49Sdanielk1977 test_memdebug_log_clear(); 838dbdc4d49Sdanielk1977 break; 8396f332c18Sdanielk1977 } 840dbdc4d49Sdanielk1977 841dbdc4d49Sdanielk1977 case MB_LOG_SYNC: { 842b940492eSdrh #ifdef SQLITE_MEMDEBUG 843dbdc4d49Sdanielk1977 extern void sqlite3MemdebugSync(); 844dbdc4d49Sdanielk1977 test_memdebug_log_clear(); 845dbdc4d49Sdanielk1977 mallocLogEnabled = 1; 846dbdc4d49Sdanielk1977 sqlite3MemdebugSync(); 847b940492eSdrh #endif 848dbdc4d49Sdanielk1977 break; 8496f332c18Sdanielk1977 } 8506f332c18Sdanielk1977 } 8516f332c18Sdanielk1977 8526f332c18Sdanielk1977 return TCL_OK; 8536f332c18Sdanielk1977 } 8544a50aac5Sdrh 8554a50aac5Sdrh /* 8569ac3fe97Sdrh ** Usage: sqlite3_config_scratch SIZE N 8579ac3fe97Sdrh ** 8589ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. 8599ac3fe97Sdrh ** The buffer is static and is of limited size. N might be 8609ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size. 8619ac3fe97Sdrh ** The revised value of N is returned. 8629ac3fe97Sdrh ** 8639ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL. 8649ac3fe97Sdrh */ 8659ac3fe97Sdrh static int test_config_scratch( 8669ac3fe97Sdrh void * clientData, 8679ac3fe97Sdrh Tcl_Interp *interp, 8689ac3fe97Sdrh int objc, 8699ac3fe97Sdrh Tcl_Obj *CONST objv[] 8709ac3fe97Sdrh ){ 8719ac3fe97Sdrh int sz, N, rc; 8729ac3fe97Sdrh Tcl_Obj *pResult; 873f7141990Sdrh static char buf[30000]; 8749ac3fe97Sdrh if( objc!=3 ){ 8759ac3fe97Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 8769ac3fe97Sdrh return TCL_ERROR; 8779ac3fe97Sdrh } 878f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 879f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 8809ac3fe97Sdrh if( sz<0 ){ 8819ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); 882f7141990Sdrh }else{ 8839ac3fe97Sdrh int mx = sizeof(buf)/(sz+4); 8849ac3fe97Sdrh if( N>mx ) N = mx; 8859ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); 8869ac3fe97Sdrh } 8879ac3fe97Sdrh pResult = Tcl_NewObj(); 8889ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 8899ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 8909ac3fe97Sdrh Tcl_SetObjResult(interp, pResult); 8919ac3fe97Sdrh return TCL_OK; 8929ac3fe97Sdrh } 8939ac3fe97Sdrh 8949ac3fe97Sdrh /* 8959ac3fe97Sdrh ** Usage: sqlite3_config_pagecache SIZE N 8969ac3fe97Sdrh ** 8979ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. 8989ac3fe97Sdrh ** The buffer is static and is of limited size. N might be 8999ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size. 9009ac3fe97Sdrh ** The revised value of N is returned. 9019ac3fe97Sdrh ** 9029ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL. 9039ac3fe97Sdrh */ 9049ac3fe97Sdrh static int test_config_pagecache( 9059ac3fe97Sdrh void * clientData, 9069ac3fe97Sdrh Tcl_Interp *interp, 9079ac3fe97Sdrh int objc, 9089ac3fe97Sdrh Tcl_Obj *CONST objv[] 9099ac3fe97Sdrh ){ 9109ac3fe97Sdrh int sz, N, rc; 9119ac3fe97Sdrh Tcl_Obj *pResult; 9129ac3fe97Sdrh static char buf[100000]; 9139ac3fe97Sdrh if( objc!=3 ){ 9149ac3fe97Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 9159ac3fe97Sdrh return TCL_ERROR; 9169ac3fe97Sdrh } 917f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 918f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 9199ac3fe97Sdrh if( sz<0 ){ 920f7141990Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); 921f7141990Sdrh }else{ 9229ac3fe97Sdrh int mx = sizeof(buf)/(sz+4); 9239ac3fe97Sdrh if( N>mx ) N = mx; 9249ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); 9259ac3fe97Sdrh } 9269ac3fe97Sdrh pResult = Tcl_NewObj(); 9279ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 9289ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 9299ac3fe97Sdrh Tcl_SetObjResult(interp, pResult); 9309ac3fe97Sdrh return TCL_OK; 9319ac3fe97Sdrh } 9329ac3fe97Sdrh 933f7141990Sdrh /* 934c66c0e14Sdanielk1977 ** Usage: 935c66c0e14Sdanielk1977 ** 9365099be5eSdanielk1977 ** sqlite3_config_heap ?-memsys3? NBYTE NMINALLOC 9375099be5eSdanielk1977 */ 9385099be5eSdanielk1977 static int test_config_heap( 9395099be5eSdanielk1977 void * clientData, 9405099be5eSdanielk1977 Tcl_Interp *interp, 9415099be5eSdanielk1977 int objc, 9425099be5eSdanielk1977 Tcl_Obj *CONST objv[] 9435099be5eSdanielk1977 ){ 9445099be5eSdanielk1977 static char zBuf[1048576]; 9455099be5eSdanielk1977 int nByte; /* Size of buffer to pass to sqlite3_config() */ 9465099be5eSdanielk1977 int nMinAlloc; /* Size of minimum allocation */ 9475099be5eSdanielk1977 int rc; /* Return code of sqlite3_config() */ 9485099be5eSdanielk1977 int isMemsys3 = 0; /* True if the -memsys3 switch is present */ 9495099be5eSdanielk1977 9505099be5eSdanielk1977 Tcl_Obj * CONST *aArg = &objv[1]; 9515099be5eSdanielk1977 int nArg = objc-1; 9525099be5eSdanielk1977 9535099be5eSdanielk1977 if( nArg>0 && 0==strcmp("-memsys3", Tcl_GetString(aArg[0])) ){ 9545099be5eSdanielk1977 nArg--; 9555099be5eSdanielk1977 aArg++; 9565099be5eSdanielk1977 isMemsys3 = 1; 9575099be5eSdanielk1977 } 9585099be5eSdanielk1977 if( nArg!=2 ){ 9595099be5eSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "?-memsys3? NBYTE NMINALLOC"); 9605099be5eSdanielk1977 return TCL_ERROR; 9615099be5eSdanielk1977 } 9625099be5eSdanielk1977 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR; 9635099be5eSdanielk1977 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR; 9645099be5eSdanielk1977 9650d84e5b2Sdanielk1977 if( nByte==0 ){ 9660d84e5b2Sdanielk1977 sqlite3_mem_methods m; 9670d84e5b2Sdanielk1977 memset(&m, 0, sizeof(sqlite3_mem_methods)); 9680d84e5b2Sdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); 9690d84e5b2Sdanielk1977 }else{ 9705099be5eSdanielk1977 if( nByte>sizeof(zBuf) ){ 9715099be5eSdanielk1977 nByte = sizeof(zBuf); 9725099be5eSdanielk1977 } 9735099be5eSdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); 9740d84e5b2Sdanielk1977 if( isMemsys3 && rc==SQLITE_OK ){ 9750d84e5b2Sdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_MEMSYS3); 9760d84e5b2Sdanielk1977 } 9770d84e5b2Sdanielk1977 } 9785099be5eSdanielk1977 9795099be5eSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 9805099be5eSdanielk1977 return TCL_OK; 9815099be5eSdanielk1977 } 9825099be5eSdanielk1977 9835099be5eSdanielk1977 /* 9845099be5eSdanielk1977 ** Usage: 9855099be5eSdanielk1977 ** 986c66c0e14Sdanielk1977 ** sqlite3_dump_memsys3 FILENAME 987c66c0e14Sdanielk1977 ** sqlite3_dump_memsys5 FILENAME 98832155ef0Sdanielk1977 ** 98932155ef0Sdanielk1977 ** Write a summary of unfreed memsys3 allocations to FILENAME. 99032155ef0Sdanielk1977 */ 99132155ef0Sdanielk1977 static int test_dump_memsys3( 99232155ef0Sdanielk1977 void * clientData, 99332155ef0Sdanielk1977 Tcl_Interp *interp, 99432155ef0Sdanielk1977 int objc, 99532155ef0Sdanielk1977 Tcl_Obj *CONST objv[] 99632155ef0Sdanielk1977 ){ 99732155ef0Sdanielk1977 if( objc!=2 ){ 99832155ef0Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 99932155ef0Sdanielk1977 return TCL_ERROR; 100032155ef0Sdanielk1977 } 1001c66c0e14Sdanielk1977 1002c66c0e14Sdanielk1977 switch( (int)clientData ){ 10030d84e5b2Sdanielk1977 case 3: { 1004c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS3 100532155ef0Sdanielk1977 extern void sqlite3Memsys3Dump(const char*); 100632155ef0Sdanielk1977 sqlite3Memsys3Dump(Tcl_GetString(objv[1])); 1007c66c0e14Sdanielk1977 break; 100832155ef0Sdanielk1977 #endif 1009c66c0e14Sdanielk1977 } 10100d84e5b2Sdanielk1977 case 5: { 1011c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS5 1012c66c0e14Sdanielk1977 extern void sqlite3Memsys5Dump(const char*); 1013c66c0e14Sdanielk1977 sqlite3Memsys5Dump(Tcl_GetString(objv[1])); 1014c66c0e14Sdanielk1977 break; 1015c66c0e14Sdanielk1977 #endif 1016c66c0e14Sdanielk1977 } 1017c66c0e14Sdanielk1977 } 101832155ef0Sdanielk1977 return TCL_OK; 101932155ef0Sdanielk1977 } 102032155ef0Sdanielk1977 102132155ef0Sdanielk1977 /* 1022f7141990Sdrh ** Usage: sqlite3_status OPCODE RESETFLAG 1023f7141990Sdrh ** 1024f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return 1025f7141990Sdrh ** code, the current value, and the high-water mark value. 1026f7141990Sdrh */ 1027f7141990Sdrh static int test_status( 1028f7141990Sdrh void * clientData, 1029f7141990Sdrh Tcl_Interp *interp, 1030f7141990Sdrh int objc, 1031f7141990Sdrh Tcl_Obj *CONST objv[] 1032f7141990Sdrh ){ 1033f7141990Sdrh int rc, iValue, mxValue; 1034f7141990Sdrh int i, op, resetFlag; 1035f7141990Sdrh const char *zOpName; 1036f7141990Sdrh static const struct { 1037f7141990Sdrh const char *zName; 1038f7141990Sdrh int op; 1039f7141990Sdrh } aOp[] = { 1040f7141990Sdrh { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, 1041f7141990Sdrh { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, 1042f7141990Sdrh { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, 1043f7141990Sdrh { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, 1044f7141990Sdrh { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, 1045f7141990Sdrh { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, 104622c2403aSdrh { "SQLITE_STATUS_FAILSAFE", SQLITE_STATUS_FAILSAFE }, 1047f7141990Sdrh }; 1048f7141990Sdrh Tcl_Obj *pResult; 1049f7141990Sdrh if( objc!=3 ){ 1050f7141990Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1051f7141990Sdrh return TCL_ERROR; 1052f7141990Sdrh } 1053f7141990Sdrh zOpName = Tcl_GetString(objv[1]); 1054f7141990Sdrh for(i=0; i<ArraySize(aOp); i++){ 1055f7141990Sdrh if( strcmp(aOp[i].zName, zOpName)==0 ){ 1056f7141990Sdrh op = aOp[i].op; 1057f7141990Sdrh break; 1058f7141990Sdrh } 1059f7141990Sdrh } 1060f7141990Sdrh if( i>=ArraySize(aOp) ){ 1061f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; 1062f7141990Sdrh } 1063f7141990Sdrh if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; 1064*af005fbcSdrh iValue = 0; 1065*af005fbcSdrh mxValue = 0; 1066f7141990Sdrh rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); 1067f7141990Sdrh pResult = Tcl_NewObj(); 1068f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1069f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1070f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1071f7141990Sdrh Tcl_SetObjResult(interp, pResult); 1072f7141990Sdrh return TCL_OK; 1073f7141990Sdrh } 10749ac3fe97Sdrh 10759ac3fe97Sdrh /* 1076d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN 1077d09414cdSdanielk1977 */ 1078d09414cdSdanielk1977 static int test_install_malloc_faultsim( 1079d09414cdSdanielk1977 void * clientData, 1080d09414cdSdanielk1977 Tcl_Interp *interp, 1081d09414cdSdanielk1977 int objc, 1082d09414cdSdanielk1977 Tcl_Obj *CONST objv[] 1083d09414cdSdanielk1977 ){ 1084d09414cdSdanielk1977 int rc; 1085d09414cdSdanielk1977 int isInstall; 1086d09414cdSdanielk1977 1087d09414cdSdanielk1977 if( objc!=2 ){ 1088d09414cdSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 1089d09414cdSdanielk1977 return TCL_ERROR; 1090d09414cdSdanielk1977 } 1091d09414cdSdanielk1977 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 1092d09414cdSdanielk1977 return TCL_ERROR; 1093d09414cdSdanielk1977 } 1094ef05f2dfSdanielk1977 rc = faultsimInstall(isInstall); 1095d09414cdSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1096d09414cdSdanielk1977 return TCL_OK; 1097d09414cdSdanielk1977 } 1098d09414cdSdanielk1977 1099d09414cdSdanielk1977 /* 11002f999a67Sdrh ** Register commands with the TCL interpreter. 11012f999a67Sdrh */ 11022f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 11032f999a67Sdrh static struct { 11042f999a67Sdrh char *zName; 11052f999a67Sdrh Tcl_ObjCmdProc *xProc; 1106c66c0e14Sdanielk1977 int clientData; 11072f999a67Sdrh } aObjCmd[] = { 1108c66c0e14Sdanielk1977 { "sqlite3_malloc", test_malloc ,0. }, 1109c66c0e14Sdanielk1977 { "sqlite3_realloc", test_realloc ,0. }, 1110c66c0e14Sdanielk1977 { "sqlite3_free", test_free ,0. }, 1111c66c0e14Sdanielk1977 { "memset", test_memset ,0. }, 1112c66c0e14Sdanielk1977 { "memget", test_memget ,0. }, 1113c66c0e14Sdanielk1977 { "sqlite3_memory_used", test_memory_used ,0. }, 1114c66c0e14Sdanielk1977 { "sqlite3_memory_highwater", test_memory_highwater ,0. }, 1115c66c0e14Sdanielk1977 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0. }, 1116c66c0e14Sdanielk1977 { "sqlite3_memdebug_dump", test_memdebug_dump ,0. }, 1117c66c0e14Sdanielk1977 { "sqlite3_memdebug_fail", test_memdebug_fail ,0. }, 1118c66c0e14Sdanielk1977 { "sqlite3_memdebug_pending", test_memdebug_pending ,0. }, 1119c66c0e14Sdanielk1977 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0. }, 1120c66c0e14Sdanielk1977 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0. }, 1121c66c0e14Sdanielk1977 { "sqlite3_memdebug_log", test_memdebug_log ,0. }, 1122c66c0e14Sdanielk1977 { "sqlite3_config_scratch", test_config_scratch ,0. }, 1123c66c0e14Sdanielk1977 { "sqlite3_config_pagecache", test_config_pagecache ,0. }, 1124c66c0e14Sdanielk1977 { "sqlite3_status", test_status ,0. }, 1125c66c0e14Sdanielk1977 { "install_malloc_faultsim", test_install_malloc_faultsim ,0. }, 11265099be5eSdanielk1977 { "sqlite3_config_heap", test_config_heap ,0 }, 11270d84e5b2Sdanielk1977 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, 11280d84e5b2Sdanielk1977 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 } 11292f999a67Sdrh }; 11302f999a67Sdrh int i; 11312f999a67Sdrh for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 1132c66c0e14Sdanielk1977 ClientData c = (ClientData)aObjCmd[i].clientData; 1133c66c0e14Sdanielk1977 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); 11342f999a67Sdrh } 11352f999a67Sdrh return TCL_OK; 11362f999a67Sdrh } 1137ef05f2dfSdanielk1977 #endif 1138