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 */ 162f999a67Sdrh #include "sqliteInt.h" 172f999a67Sdrh #include "tcl.h" 182f999a67Sdrh #include <stdlib.h> 192f999a67Sdrh #include <string.h> 202f999a67Sdrh #include <assert.h> 212f999a67Sdrh 22ef05f2dfSdanielk1977 /* 23ef05f2dfSdanielk1977 ** This structure is used to encapsulate the global state variables used 24ef05f2dfSdanielk1977 ** by malloc() fault simulation. 25ef05f2dfSdanielk1977 */ 26ef05f2dfSdanielk1977 static struct MemFault { 27ef05f2dfSdanielk1977 int iCountdown; /* Number of pending successes before a failure */ 28ef05f2dfSdanielk1977 int nRepeat; /* Number of times to repeat the failure */ 29ef05f2dfSdanielk1977 int nBenign; /* Number of benign failures seen since last config */ 30ef05f2dfSdanielk1977 int nFail; /* Number of failures seen since last config */ 31ef05f2dfSdanielk1977 u8 enable; /* True if enabled */ 32ef05f2dfSdanielk1977 int isInstalled; /* True if the fault simulation layer is installed */ 332d1d86fbSdanielk1977 int isBenignMode; /* True if malloc failures are considered benign */ 34ef05f2dfSdanielk1977 sqlite3_mem_methods m; /* 'Real' malloc implementation */ 35ef05f2dfSdanielk1977 } memfault; 36ef05f2dfSdanielk1977 37ef05f2dfSdanielk1977 /* 38ef05f2dfSdanielk1977 ** This routine exists as a place to set a breakpoint that will 39ef05f2dfSdanielk1977 ** fire on any simulated malloc() failure. 40ef05f2dfSdanielk1977 */ 41ef05f2dfSdanielk1977 static void sqlite3Fault(void){ 42ef05f2dfSdanielk1977 static int cnt = 0; 43ef05f2dfSdanielk1977 cnt++; 44ef05f2dfSdanielk1977 } 45ef05f2dfSdanielk1977 46ef05f2dfSdanielk1977 /* 47ef05f2dfSdanielk1977 ** Check to see if a fault should be simulated. Return true to simulate 48ef05f2dfSdanielk1977 ** the fault. Return false if the fault should not be simulated. 49ef05f2dfSdanielk1977 */ 5064aca191Sdanielk1977 static int faultsimStep(void){ 51ef05f2dfSdanielk1977 if( likely(!memfault.enable) ){ 52ef05f2dfSdanielk1977 return 0; 53ef05f2dfSdanielk1977 } 54ef05f2dfSdanielk1977 if( memfault.iCountdown>0 ){ 55ef05f2dfSdanielk1977 memfault.iCountdown--; 56ef05f2dfSdanielk1977 return 0; 57ef05f2dfSdanielk1977 } 58ef05f2dfSdanielk1977 sqlite3Fault(); 59ef05f2dfSdanielk1977 memfault.nFail++; 602d1d86fbSdanielk1977 if( memfault.isBenignMode>0 ){ 61ef05f2dfSdanielk1977 memfault.nBenign++; 62ef05f2dfSdanielk1977 } 63ef05f2dfSdanielk1977 memfault.nRepeat--; 64ef05f2dfSdanielk1977 if( memfault.nRepeat<=0 ){ 65ef05f2dfSdanielk1977 memfault.enable = 0; 66ef05f2dfSdanielk1977 } 67ef05f2dfSdanielk1977 return 1; 68ef05f2dfSdanielk1977 } 69ef05f2dfSdanielk1977 70ef05f2dfSdanielk1977 /* 71ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation 72ef05f2dfSdanielk1977 ** logic. 73ef05f2dfSdanielk1977 */ 74ef05f2dfSdanielk1977 static void *faultsimMalloc(int n){ 75ef05f2dfSdanielk1977 void *p = 0; 76ef05f2dfSdanielk1977 if( !faultsimStep() ){ 77ef05f2dfSdanielk1977 p = memfault.m.xMalloc(n); 78ef05f2dfSdanielk1977 } 79ef05f2dfSdanielk1977 return p; 80ef05f2dfSdanielk1977 } 81ef05f2dfSdanielk1977 82ef05f2dfSdanielk1977 83ef05f2dfSdanielk1977 /* 84ef05f2dfSdanielk1977 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation 85ef05f2dfSdanielk1977 ** logic. 86ef05f2dfSdanielk1977 */ 87ef05f2dfSdanielk1977 static void *faultsimRealloc(void *pOld, int n){ 88ef05f2dfSdanielk1977 void *p = 0; 89ef05f2dfSdanielk1977 if( !faultsimStep() ){ 90ef05f2dfSdanielk1977 p = memfault.m.xRealloc(pOld, n); 91ef05f2dfSdanielk1977 } 92ef05f2dfSdanielk1977 return p; 93ef05f2dfSdanielk1977 } 94ef05f2dfSdanielk1977 95ef05f2dfSdanielk1977 /* 96ef05f2dfSdanielk1977 ** The following method calls are passed directly through to the underlying 97ef05f2dfSdanielk1977 ** malloc system: 98ef05f2dfSdanielk1977 ** 99ef05f2dfSdanielk1977 ** xFree 100ef05f2dfSdanielk1977 ** xSize 101ef05f2dfSdanielk1977 ** xRoundup 102ef05f2dfSdanielk1977 ** xInit 103ef05f2dfSdanielk1977 ** xShutdown 104ef05f2dfSdanielk1977 */ 105ef05f2dfSdanielk1977 static void faultsimFree(void *p){ 106ef05f2dfSdanielk1977 memfault.m.xFree(p); 107ef05f2dfSdanielk1977 } 108ef05f2dfSdanielk1977 static int faultsimSize(void *p){ 109ef05f2dfSdanielk1977 return memfault.m.xSize(p); 110ef05f2dfSdanielk1977 } 111ef05f2dfSdanielk1977 static int faultsimRoundup(int n){ 112ef05f2dfSdanielk1977 return memfault.m.xRoundup(n); 113ef05f2dfSdanielk1977 } 114ef05f2dfSdanielk1977 static int faultsimInit(void *p){ 115ef05f2dfSdanielk1977 return memfault.m.xInit(memfault.m.pAppData); 116ef05f2dfSdanielk1977 } 117ef05f2dfSdanielk1977 static void faultsimShutdown(void *p){ 118ef05f2dfSdanielk1977 memfault.m.xShutdown(memfault.m.pAppData); 119ef05f2dfSdanielk1977 } 120ef05f2dfSdanielk1977 121ef05f2dfSdanielk1977 /* 122ef05f2dfSdanielk1977 ** This routine configures the malloc failure simulation. After 123ef05f2dfSdanielk1977 ** calling this routine, the next nDelay mallocs will succeed, followed 124ef05f2dfSdanielk1977 ** by a block of nRepeat failures, after which malloc() calls will begin 125ef05f2dfSdanielk1977 ** to succeed again. 126ef05f2dfSdanielk1977 */ 127ef05f2dfSdanielk1977 static void faultsimConfig(int nDelay, int nRepeat){ 128ef05f2dfSdanielk1977 memfault.iCountdown = nDelay; 129ef05f2dfSdanielk1977 memfault.nRepeat = nRepeat; 130ef05f2dfSdanielk1977 memfault.nBenign = 0; 131ef05f2dfSdanielk1977 memfault.nFail = 0; 132ef05f2dfSdanielk1977 memfault.enable = nDelay>=0; 133b48c1f19Sdanielk1977 134b48c1f19Sdanielk1977 /* Sometimes, when running multi-threaded tests, the isBenignMode 135b48c1f19Sdanielk1977 ** variable is not properly incremented/decremented so that it is 136b48c1f19Sdanielk1977 ** 0 when not inside a benign malloc block. This doesn't affect 137b48c1f19Sdanielk1977 ** the multi-threaded tests, as they do not use this system. But 138b48c1f19Sdanielk1977 ** it does affect OOM tests run later in the same process. So 139b48c1f19Sdanielk1977 ** zero the variable here, just to be sure. 140b48c1f19Sdanielk1977 */ 141b48c1f19Sdanielk1977 memfault.isBenignMode = 0; 142ef05f2dfSdanielk1977 } 143ef05f2dfSdanielk1977 144ef05f2dfSdanielk1977 /* 145ef05f2dfSdanielk1977 ** Return the number of faults (both hard and benign faults) that have 146ef05f2dfSdanielk1977 ** occurred since the injector was last configured. 147ef05f2dfSdanielk1977 */ 148ef05f2dfSdanielk1977 static int faultsimFailures(void){ 149ef05f2dfSdanielk1977 return memfault.nFail; 150ef05f2dfSdanielk1977 } 151ef05f2dfSdanielk1977 152ef05f2dfSdanielk1977 /* 153ef05f2dfSdanielk1977 ** Return the number of benign faults that have occurred since the 154ef05f2dfSdanielk1977 ** injector was last configured. 155ef05f2dfSdanielk1977 */ 156ef05f2dfSdanielk1977 static int faultsimBenignFailures(void){ 157ef05f2dfSdanielk1977 return memfault.nBenign; 158ef05f2dfSdanielk1977 } 159ef05f2dfSdanielk1977 160ef05f2dfSdanielk1977 /* 161ef05f2dfSdanielk1977 ** Return the number of successes that will occur before the next failure. 162ef05f2dfSdanielk1977 ** If no failures are scheduled, return -1. 163ef05f2dfSdanielk1977 */ 164ef05f2dfSdanielk1977 static int faultsimPending(void){ 165ef05f2dfSdanielk1977 if( memfault.enable ){ 166ef05f2dfSdanielk1977 return memfault.iCountdown; 167ef05f2dfSdanielk1977 }else{ 168ef05f2dfSdanielk1977 return -1; 169ef05f2dfSdanielk1977 } 170ef05f2dfSdanielk1977 } 171ef05f2dfSdanielk1977 1722d1d86fbSdanielk1977 1732d1d86fbSdanielk1977 static void faultsimBeginBenign(void){ 1742d1d86fbSdanielk1977 memfault.isBenignMode++; 1752d1d86fbSdanielk1977 } 1762d1d86fbSdanielk1977 static void faultsimEndBenign(void){ 1772d1d86fbSdanielk1977 memfault.isBenignMode--; 1782d1d86fbSdanielk1977 } 1792d1d86fbSdanielk1977 180ef05f2dfSdanielk1977 /* 181ef05f2dfSdanielk1977 ** Add or remove the fault-simulation layer using sqlite3_config(). If 182ef05f2dfSdanielk1977 ** the argument is non-zero, the 183ef05f2dfSdanielk1977 */ 184ef05f2dfSdanielk1977 static int faultsimInstall(int install){ 185ef05f2dfSdanielk1977 static struct sqlite3_mem_methods m = { 186ef05f2dfSdanielk1977 faultsimMalloc, /* xMalloc */ 187ef05f2dfSdanielk1977 faultsimFree, /* xFree */ 188ef05f2dfSdanielk1977 faultsimRealloc, /* xRealloc */ 189ef05f2dfSdanielk1977 faultsimSize, /* xSize */ 190ef05f2dfSdanielk1977 faultsimRoundup, /* xRoundup */ 191ef05f2dfSdanielk1977 faultsimInit, /* xInit */ 192ef05f2dfSdanielk1977 faultsimShutdown, /* xShutdown */ 193ef05f2dfSdanielk1977 0 /* pAppData */ 194ef05f2dfSdanielk1977 }; 195ef05f2dfSdanielk1977 int rc; 196ef05f2dfSdanielk1977 197ef05f2dfSdanielk1977 install = (install ? 1 : 0); 198ef05f2dfSdanielk1977 assert(memfault.isInstalled==1 || memfault.isInstalled==0); 199ef05f2dfSdanielk1977 200ef05f2dfSdanielk1977 if( install==memfault.isInstalled ){ 201ef05f2dfSdanielk1977 return SQLITE_ERROR; 202ef05f2dfSdanielk1977 } 203ef05f2dfSdanielk1977 2042d1d86fbSdanielk1977 if( install ){ 205ef05f2dfSdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m); 206ef05f2dfSdanielk1977 assert(memfault.m.xMalloc); 207ef05f2dfSdanielk1977 if( rc==SQLITE_OK ){ 208ef05f2dfSdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); 209ef05f2dfSdanielk1977 } 2102d1d86fbSdanielk1977 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 2112d1d86fbSdanielk1977 faultsimBeginBenign, faultsimEndBenign 2122d1d86fbSdanielk1977 ); 2132d1d86fbSdanielk1977 }else{ 2141b67f3caSdrh sqlite3_mem_methods m; 2152d1d86fbSdanielk1977 assert(memfault.m.xMalloc); 2161b67f3caSdrh 2171b67f3caSdrh /* One should be able to reset the default memory allocator by storing 2181b67f3caSdrh ** a zeroed allocator then calling GETMALLOC. */ 2191b67f3caSdrh memset(&m, 0, sizeof(m)); 2201b67f3caSdrh sqlite3_config(SQLITE_CONFIG_MALLOC, &m); 2211b67f3caSdrh sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m); 2221b67f3caSdrh assert( memcmp(&m, &memfault.m, sizeof(m))==0 ); 2231b67f3caSdrh 2242d1d86fbSdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m); 2252d1d86fbSdanielk1977 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0); 2262d1d86fbSdanielk1977 } 227ef05f2dfSdanielk1977 228ef05f2dfSdanielk1977 if( rc==SQLITE_OK ){ 229ef05f2dfSdanielk1977 memfault.isInstalled = 1; 230ef05f2dfSdanielk1977 } 231ef05f2dfSdanielk1977 return rc; 232ef05f2dfSdanielk1977 } 233ef05f2dfSdanielk1977 234ef05f2dfSdanielk1977 #ifdef SQLITE_TEST 235ef05f2dfSdanielk1977 236ef05f2dfSdanielk1977 /* 237ef05f2dfSdanielk1977 ** This function is implemented in test1.c. Returns a pointer to a static 238ef05f2dfSdanielk1977 ** buffer containing the symbolic SQLite error code that corresponds to 239ef05f2dfSdanielk1977 ** the least-significant 8-bits of the integer passed as an argument. 240ef05f2dfSdanielk1977 ** For example: 241ef05f2dfSdanielk1977 ** 242ef05f2dfSdanielk1977 ** sqlite3TestErrorName(1) -> "SQLITE_ERROR" 243ef05f2dfSdanielk1977 */ 244d09414cdSdanielk1977 const char *sqlite3TestErrorName(int); 245d09414cdSdanielk1977 2462f999a67Sdrh /* 2472f999a67Sdrh ** Transform pointers to text and back again 2482f999a67Sdrh */ 2492f999a67Sdrh static void pointerToText(void *p, char *z){ 2502f999a67Sdrh static const char zHex[] = "0123456789abcdef"; 2512f999a67Sdrh int i, k; 2524a50aac5Sdrh unsigned int u; 2534a50aac5Sdrh sqlite3_uint64 n; 2548a42cbd3Sdrh if( p==0 ){ 2558a42cbd3Sdrh strcpy(z, "0"); 2568a42cbd3Sdrh return; 2578a42cbd3Sdrh } 2584a50aac5Sdrh if( sizeof(n)==sizeof(p) ){ 2594a50aac5Sdrh memcpy(&n, &p, sizeof(p)); 2604a50aac5Sdrh }else if( sizeof(u)==sizeof(p) ){ 2614a50aac5Sdrh memcpy(&u, &p, sizeof(u)); 2624a50aac5Sdrh n = u; 2634a50aac5Sdrh }else{ 2644a50aac5Sdrh assert( 0 ); 2654a50aac5Sdrh } 2662f999a67Sdrh for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 2672f999a67Sdrh z[k] = zHex[n&0xf]; 2682f999a67Sdrh n >>= 4; 2692f999a67Sdrh } 2702f999a67Sdrh z[sizeof(p)*2] = 0; 2712f999a67Sdrh } 2722f999a67Sdrh static int hexToInt(int h){ 2732f999a67Sdrh if( h>='0' && h<='9' ){ 2742f999a67Sdrh return h - '0'; 2752f999a67Sdrh }else if( h>='a' && h<='f' ){ 2762f999a67Sdrh return h - 'a' + 10; 2772f999a67Sdrh }else{ 2782f999a67Sdrh return -1; 2792f999a67Sdrh } 2802f999a67Sdrh } 2812f999a67Sdrh static int textToPointer(const char *z, void **pp){ 2822f999a67Sdrh sqlite3_uint64 n = 0; 2832f999a67Sdrh int i; 2844a50aac5Sdrh unsigned int u; 2852f999a67Sdrh for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 2862f999a67Sdrh int v; 2872f999a67Sdrh v = hexToInt(*z++); 2882f999a67Sdrh if( v<0 ) return TCL_ERROR; 2892f999a67Sdrh n = n*16 + v; 2902f999a67Sdrh } 2912f999a67Sdrh if( *z!=0 ) return TCL_ERROR; 2924a50aac5Sdrh if( sizeof(n)==sizeof(*pp) ){ 2934a50aac5Sdrh memcpy(pp, &n, sizeof(n)); 2944a50aac5Sdrh }else if( sizeof(u)==sizeof(*pp) ){ 2954a50aac5Sdrh u = (unsigned int)n; 2964a50aac5Sdrh memcpy(pp, &u, sizeof(u)); 2974a50aac5Sdrh }else{ 2984a50aac5Sdrh assert( 0 ); 2994a50aac5Sdrh } 3002f999a67Sdrh return TCL_OK; 3012f999a67Sdrh } 3022f999a67Sdrh 3032f999a67Sdrh /* 3042f999a67Sdrh ** Usage: sqlite3_malloc NBYTES 3052f999a67Sdrh ** 3062f999a67Sdrh ** Raw test interface for sqlite3_malloc(). 3072f999a67Sdrh */ 3082f999a67Sdrh static int test_malloc( 3092f999a67Sdrh void * clientData, 3102f999a67Sdrh Tcl_Interp *interp, 3112f999a67Sdrh int objc, 3122f999a67Sdrh Tcl_Obj *CONST objv[] 3132f999a67Sdrh ){ 3142f999a67Sdrh int nByte; 3152f999a67Sdrh void *p; 3162f999a67Sdrh char zOut[100]; 3172f999a67Sdrh if( objc!=2 ){ 3182f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 3192f999a67Sdrh return TCL_ERROR; 3202f999a67Sdrh } 3212f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 3222f999a67Sdrh p = sqlite3_malloc((unsigned)nByte); 3232f999a67Sdrh pointerToText(p, zOut); 3242f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 3252f999a67Sdrh return TCL_OK; 3262f999a67Sdrh } 3272f999a67Sdrh 3282f999a67Sdrh /* 3292f999a67Sdrh ** Usage: sqlite3_realloc PRIOR NBYTES 3302f999a67Sdrh ** 3312f999a67Sdrh ** Raw test interface for sqlite3_realloc(). 3322f999a67Sdrh */ 3332f999a67Sdrh static int test_realloc( 3342f999a67Sdrh void * clientData, 3352f999a67Sdrh Tcl_Interp *interp, 3362f999a67Sdrh int objc, 3372f999a67Sdrh Tcl_Obj *CONST objv[] 3382f999a67Sdrh ){ 3392f999a67Sdrh int nByte; 3402f999a67Sdrh void *pPrior, *p; 3412f999a67Sdrh char zOut[100]; 3422f999a67Sdrh if( objc!=3 ){ 3432f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 3442f999a67Sdrh return TCL_ERROR; 3452f999a67Sdrh } 3462f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 3472f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 3482f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 3492f999a67Sdrh return TCL_ERROR; 3502f999a67Sdrh } 3512f999a67Sdrh p = sqlite3_realloc(pPrior, (unsigned)nByte); 3522f999a67Sdrh pointerToText(p, zOut); 3532f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 3542f999a67Sdrh return TCL_OK; 3552f999a67Sdrh } 3562f999a67Sdrh 3572f999a67Sdrh /* 3582f999a67Sdrh ** Usage: sqlite3_free PRIOR 3592f999a67Sdrh ** 3602f999a67Sdrh ** Raw test interface for sqlite3_free(). 3612f999a67Sdrh */ 3622f999a67Sdrh static int test_free( 3632f999a67Sdrh void * clientData, 3642f999a67Sdrh Tcl_Interp *interp, 3652f999a67Sdrh int objc, 3662f999a67Sdrh Tcl_Obj *CONST objv[] 3672f999a67Sdrh ){ 3682f999a67Sdrh void *pPrior; 3692f999a67Sdrh if( objc!=2 ){ 3702f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 3712f999a67Sdrh return TCL_ERROR; 3722f999a67Sdrh } 3732f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 3742f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 3752f999a67Sdrh return TCL_ERROR; 3762f999a67Sdrh } 3772f999a67Sdrh sqlite3_free(pPrior); 3782f999a67Sdrh return TCL_OK; 3792f999a67Sdrh } 3802f999a67Sdrh 3812f999a67Sdrh /* 3829c7a60dfSdrh ** These routines are in test_hexio.c 3839c7a60dfSdrh */ 3849c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *); 3859c7a60dfSdrh int sqlite3TestBinToHex(char*,int); 3869c7a60dfSdrh 3879c7a60dfSdrh /* 3889c7a60dfSdrh ** Usage: memset ADDRESS SIZE HEX 3899c7a60dfSdrh ** 3909c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a 3919c7a60dfSdrh ** specified hex pattern. 3929c7a60dfSdrh */ 3939c7a60dfSdrh static int test_memset( 3949c7a60dfSdrh void * clientData, 3959c7a60dfSdrh Tcl_Interp *interp, 3969c7a60dfSdrh int objc, 3979c7a60dfSdrh Tcl_Obj *CONST objv[] 3989c7a60dfSdrh ){ 3999c7a60dfSdrh void *p; 4009c7a60dfSdrh int size, n, i; 4019c7a60dfSdrh char *zHex; 4029c7a60dfSdrh char *zOut; 4039c7a60dfSdrh char zBin[100]; 4049c7a60dfSdrh 4059c7a60dfSdrh if( objc!=4 ){ 4069c7a60dfSdrh Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX"); 4079c7a60dfSdrh return TCL_ERROR; 4089c7a60dfSdrh } 4099c7a60dfSdrh if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 4109c7a60dfSdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 4119c7a60dfSdrh return TCL_ERROR; 4129c7a60dfSdrh } 4139c7a60dfSdrh if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 4149c7a60dfSdrh return TCL_ERROR; 4159c7a60dfSdrh } 4169c7a60dfSdrh if( size<=0 ){ 4179c7a60dfSdrh Tcl_AppendResult(interp, "size must be positive", (char*)0); 4189c7a60dfSdrh return TCL_ERROR; 4199c7a60dfSdrh } 4209c7a60dfSdrh zHex = Tcl_GetStringFromObj(objv[3], &n); 4219c7a60dfSdrh if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2; 4229c7a60dfSdrh n = sqlite3TestHexToBin(zHex, n, zBin); 4239c7a60dfSdrh if( n==0 ){ 4249c7a60dfSdrh Tcl_AppendResult(interp, "no data", (char*)0); 4259c7a60dfSdrh return TCL_ERROR; 4269c7a60dfSdrh } 4279c7a60dfSdrh zOut = p; 4289c7a60dfSdrh for(i=0; i<size; i++){ 4299c7a60dfSdrh zOut[i] = zBin[i%n]; 4309c7a60dfSdrh } 4319c7a60dfSdrh return TCL_OK; 4329c7a60dfSdrh } 4339c7a60dfSdrh 4349c7a60dfSdrh /* 4359c7a60dfSdrh ** Usage: memget ADDRESS SIZE 4369c7a60dfSdrh ** 4379c7a60dfSdrh ** Return memory as hexadecimal text. 4389c7a60dfSdrh */ 4399c7a60dfSdrh static int test_memget( 4409c7a60dfSdrh void * clientData, 4419c7a60dfSdrh Tcl_Interp *interp, 4429c7a60dfSdrh int objc, 4439c7a60dfSdrh Tcl_Obj *CONST objv[] 4449c7a60dfSdrh ){ 4459c7a60dfSdrh void *p; 4469c7a60dfSdrh int size, n; 4479c7a60dfSdrh char *zBin; 4489c7a60dfSdrh char zHex[100]; 4499c7a60dfSdrh 4509c7a60dfSdrh if( objc!=3 ){ 4519c7a60dfSdrh Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE"); 4529c7a60dfSdrh return TCL_ERROR; 4539c7a60dfSdrh } 4549c7a60dfSdrh if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 4559c7a60dfSdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 4569c7a60dfSdrh return TCL_ERROR; 4579c7a60dfSdrh } 4589c7a60dfSdrh if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 4599c7a60dfSdrh return TCL_ERROR; 4609c7a60dfSdrh } 4619c7a60dfSdrh if( size<=0 ){ 4629c7a60dfSdrh Tcl_AppendResult(interp, "size must be positive", (char*)0); 4639c7a60dfSdrh return TCL_ERROR; 4649c7a60dfSdrh } 4659c7a60dfSdrh zBin = p; 4669c7a60dfSdrh while( size>0 ){ 4679c7a60dfSdrh if( size>(sizeof(zHex)-1)/2 ){ 4689c7a60dfSdrh n = (sizeof(zHex)-1)/2; 4699c7a60dfSdrh }else{ 4709c7a60dfSdrh n = size; 4719c7a60dfSdrh } 4729c7a60dfSdrh memcpy(zHex, zBin, n); 4739c7a60dfSdrh zBin += n; 4749c7a60dfSdrh size -= n; 4759c7a60dfSdrh sqlite3TestBinToHex(zHex, n); 4769c7a60dfSdrh Tcl_AppendResult(interp, zHex, (char*)0); 4779c7a60dfSdrh } 4789c7a60dfSdrh return TCL_OK; 4799c7a60dfSdrh } 4809c7a60dfSdrh 4819c7a60dfSdrh /* 4822f999a67Sdrh ** Usage: sqlite3_memory_used 4832f999a67Sdrh ** 4842f999a67Sdrh ** Raw test interface for sqlite3_memory_used(). 4852f999a67Sdrh */ 4862f999a67Sdrh static int test_memory_used( 4872f999a67Sdrh void * clientData, 4882f999a67Sdrh Tcl_Interp *interp, 4892f999a67Sdrh int objc, 4902f999a67Sdrh Tcl_Obj *CONST objv[] 4912f999a67Sdrh ){ 4922f999a67Sdrh Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 4932f999a67Sdrh return TCL_OK; 4942f999a67Sdrh } 4952f999a67Sdrh 4962f999a67Sdrh /* 4972f999a67Sdrh ** Usage: sqlite3_memory_highwater ?RESETFLAG? 4982f999a67Sdrh ** 4992f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater(). 5002f999a67Sdrh */ 5012f999a67Sdrh static int test_memory_highwater( 5022f999a67Sdrh void * clientData, 5032f999a67Sdrh Tcl_Interp *interp, 5042f999a67Sdrh int objc, 5052f999a67Sdrh Tcl_Obj *CONST objv[] 5062f999a67Sdrh ){ 5072f999a67Sdrh int resetFlag = 0; 5082f999a67Sdrh if( objc!=1 && objc!=2 ){ 5092f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 5102f999a67Sdrh return TCL_ERROR; 5112f999a67Sdrh } 5122f999a67Sdrh if( objc==2 ){ 5132f999a67Sdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 5142f999a67Sdrh } 5152f999a67Sdrh Tcl_SetObjResult(interp, 5162f999a67Sdrh Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 5172f999a67Sdrh return TCL_OK; 5182f999a67Sdrh } 5192f999a67Sdrh 5202f999a67Sdrh /* 5212f999a67Sdrh ** Usage: sqlite3_memdebug_backtrace DEPTH 5222f999a67Sdrh ** 5232f999a67Sdrh ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 5242f999a67Sdrh ** then this routine is a no-op. 5252f999a67Sdrh */ 5262f999a67Sdrh static int test_memdebug_backtrace( 5272f999a67Sdrh void * clientData, 5282f999a67Sdrh Tcl_Interp *interp, 5292f999a67Sdrh int objc, 5302f999a67Sdrh Tcl_Obj *CONST objv[] 5312f999a67Sdrh ){ 5322f999a67Sdrh int depth; 5332f999a67Sdrh if( objc!=2 ){ 5342f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 5352f999a67Sdrh return TCL_ERROR; 5362f999a67Sdrh } 5372f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 5382f999a67Sdrh #ifdef SQLITE_MEMDEBUG 5392f999a67Sdrh { 54049e4fd71Sdrh extern void sqlite3MemdebugBacktrace(int); 54149e4fd71Sdrh sqlite3MemdebugBacktrace(depth); 5422f999a67Sdrh } 5432f999a67Sdrh #endif 5442f999a67Sdrh return TCL_OK; 5452f999a67Sdrh } 5462f999a67Sdrh 5472f999a67Sdrh /* 5482f999a67Sdrh ** Usage: sqlite3_memdebug_dump FILENAME 5492f999a67Sdrh ** 5502f999a67Sdrh ** Write a summary of unfreed memory to FILENAME. 5512f999a67Sdrh */ 5522f999a67Sdrh static int test_memdebug_dump( 5532f999a67Sdrh void * clientData, 5542f999a67Sdrh Tcl_Interp *interp, 5552f999a67Sdrh int objc, 5562f999a67Sdrh Tcl_Obj *CONST objv[] 5572f999a67Sdrh ){ 5582f999a67Sdrh if( objc!=2 ){ 5592f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 5602f999a67Sdrh return TCL_ERROR; 5612f999a67Sdrh } 5622d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ 5632d7636e2Sdrh || defined(SQLITE_POW2_MEMORY_SIZE) 5642f999a67Sdrh { 56549e4fd71Sdrh extern void sqlite3MemdebugDump(const char*); 56649e4fd71Sdrh sqlite3MemdebugDump(Tcl_GetString(objv[1])); 5672f999a67Sdrh } 5682f999a67Sdrh #endif 5692f999a67Sdrh return TCL_OK; 5702f999a67Sdrh } 5712f999a67Sdrh 572a7a8e14bSdanielk1977 /* 573a7a8e14bSdanielk1977 ** Usage: sqlite3_memdebug_malloc_count 574a7a8e14bSdanielk1977 ** 575a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called. 576a7a8e14bSdanielk1977 */ 577a7a8e14bSdanielk1977 static int test_memdebug_malloc_count( 578a7a8e14bSdanielk1977 void * clientData, 579a7a8e14bSdanielk1977 Tcl_Interp *interp, 580a7a8e14bSdanielk1977 int objc, 581a7a8e14bSdanielk1977 Tcl_Obj *CONST objv[] 582a7a8e14bSdanielk1977 ){ 583a7a8e14bSdanielk1977 int nMalloc = -1; 584a7a8e14bSdanielk1977 if( objc!=1 ){ 585a7a8e14bSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, ""); 586a7a8e14bSdanielk1977 return TCL_ERROR; 587a7a8e14bSdanielk1977 } 588a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG) 589a7a8e14bSdanielk1977 { 59049e4fd71Sdrh extern int sqlite3MemdebugMallocCount(); 59149e4fd71Sdrh nMalloc = sqlite3MemdebugMallocCount(); 592a7a8e14bSdanielk1977 } 593a7a8e14bSdanielk1977 #endif 594a7a8e14bSdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); 595a7a8e14bSdanielk1977 return TCL_OK; 596a7a8e14bSdanielk1977 } 597a7a8e14bSdanielk1977 5982f999a67Sdrh 5992f999a67Sdrh /* 600a1644fd8Sdanielk1977 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? 601a1644fd8Sdanielk1977 ** 602a1644fd8Sdanielk1977 ** where options are: 603a1644fd8Sdanielk1977 ** 604643167ffSdrh ** -repeat <count> 605a1644fd8Sdanielk1977 ** -benigncnt <varname> 6060e6f1546Sdrh ** 6070e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes. 608643167ffSdrh ** If a repeat count is specified, the fault is repeated that many 609643167ffSdrh ** times. 6100e6f1546Sdrh ** 6110e6f1546Sdrh ** Each call to this routine overrides the prior counter value. 6120e6f1546Sdrh ** This routine returns the number of simulated failures that have 6130e6f1546Sdrh ** happened since the previous call to this routine. 6140e6f1546Sdrh ** 6150e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1. 6160e6f1546Sdrh */ 6170e6f1546Sdrh static int test_memdebug_fail( 6180e6f1546Sdrh void * clientData, 6190e6f1546Sdrh Tcl_Interp *interp, 6200e6f1546Sdrh int objc, 6210e6f1546Sdrh Tcl_Obj *CONST objv[] 6220e6f1546Sdrh ){ 623a1644fd8Sdanielk1977 int ii; 6240e6f1546Sdrh int iFail; 625643167ffSdrh int nRepeat = 1; 626a1644fd8Sdanielk1977 Tcl_Obj *pBenignCnt = 0; 627643167ffSdrh int nBenign; 6280e6f1546Sdrh int nFail = 0; 629a1644fd8Sdanielk1977 630a1644fd8Sdanielk1977 if( objc<2 ){ 631a1644fd8Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); 6320e6f1546Sdrh return TCL_ERROR; 6330e6f1546Sdrh } 6340e6f1546Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 635a1644fd8Sdanielk1977 636a1644fd8Sdanielk1977 for(ii=2; ii<objc; ii+=2){ 637a1644fd8Sdanielk1977 int nOption; 638a1644fd8Sdanielk1977 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); 639a1644fd8Sdanielk1977 char *zErr = 0; 640a1644fd8Sdanielk1977 641a1644fd8Sdanielk1977 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ 642a1644fd8Sdanielk1977 if( ii==(objc-1) ){ 643a1644fd8Sdanielk1977 zErr = "option requires an argument: "; 644ed138fb3Sdrh }else{ 645643167ffSdrh if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ 646a1644fd8Sdanielk1977 return TCL_ERROR; 647ed138fb3Sdrh } 648a1644fd8Sdanielk1977 } 649a1644fd8Sdanielk1977 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ 650a1644fd8Sdanielk1977 if( ii==(objc-1) ){ 651a1644fd8Sdanielk1977 zErr = "option requires an argument: "; 652a1644fd8Sdanielk1977 }else{ 653a1644fd8Sdanielk1977 pBenignCnt = objv[ii+1]; 654a1644fd8Sdanielk1977 } 655a1644fd8Sdanielk1977 }else{ 656a1644fd8Sdanielk1977 zErr = "unknown option: "; 657a1644fd8Sdanielk1977 } 658a1644fd8Sdanielk1977 659a1644fd8Sdanielk1977 if( zErr ){ 660a1644fd8Sdanielk1977 Tcl_AppendResult(interp, zErr, zOption, 0); 661a1644fd8Sdanielk1977 return TCL_ERROR; 662a1644fd8Sdanielk1977 } 663a1644fd8Sdanielk1977 } 664a1644fd8Sdanielk1977 665ef05f2dfSdanielk1977 nBenign = faultsimBenignFailures(); 666ef05f2dfSdanielk1977 nFail = faultsimFailures(); 667ef05f2dfSdanielk1977 faultsimConfig(iFail, nRepeat); 668ef05f2dfSdanielk1977 669a1644fd8Sdanielk1977 if( pBenignCnt ){ 670643167ffSdrh Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); 671a1644fd8Sdanielk1977 } 6720e6f1546Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 6730e6f1546Sdrh return TCL_OK; 6740e6f1546Sdrh } 6750e6f1546Sdrh 676cd03724cSdanielk1977 /* 677cd03724cSdanielk1977 ** Usage: sqlite3_memdebug_pending 678cd03724cSdanielk1977 ** 679cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a 680cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that 681cd03724cSdanielk1977 ** no malloc() failure is scheduled. 682cd03724cSdanielk1977 */ 683cd03724cSdanielk1977 static int test_memdebug_pending( 684cd03724cSdanielk1977 void * clientData, 685cd03724cSdanielk1977 Tcl_Interp *interp, 686cd03724cSdanielk1977 int objc, 687cd03724cSdanielk1977 Tcl_Obj *CONST objv[] 688cd03724cSdanielk1977 ){ 6895efaf070Sdrh int nPending; 690cd03724cSdanielk1977 if( objc!=1 ){ 691cd03724cSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, ""); 692cd03724cSdanielk1977 return TCL_ERROR; 693cd03724cSdanielk1977 } 694ef05f2dfSdanielk1977 nPending = faultsimPending(); 695ed13d98cSdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending)); 696cd03724cSdanielk1977 return TCL_OK; 697cd03724cSdanielk1977 } 698cd03724cSdanielk1977 6990e6f1546Sdrh 7000e6f1546Sdrh /* 7014a50aac5Sdrh ** Usage: sqlite3_memdebug_settitle TITLE 7024a50aac5Sdrh ** 7034a50aac5Sdrh ** Set a title string stored with each allocation. The TITLE is 7044a50aac5Sdrh ** typically the name of the test that was running when the 7054a50aac5Sdrh ** allocation occurred. The TITLE is stored with the allocation 7064a50aac5Sdrh ** and can be used to figure out which tests are leaking memory. 7074a50aac5Sdrh ** 7084a50aac5Sdrh ** Each title overwrite the previous. 7094a50aac5Sdrh */ 7104a50aac5Sdrh static int test_memdebug_settitle( 7114a50aac5Sdrh void * clientData, 7124a50aac5Sdrh Tcl_Interp *interp, 7134a50aac5Sdrh int objc, 7144a50aac5Sdrh Tcl_Obj *CONST objv[] 7154a50aac5Sdrh ){ 7164a50aac5Sdrh if( objc!=2 ){ 7174a50aac5Sdrh Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); 7184a50aac5Sdrh return TCL_ERROR; 7194a50aac5Sdrh } 7204a50aac5Sdrh #ifdef SQLITE_MEMDEBUG 7214a50aac5Sdrh { 722caffb1a5Sdrh const char *zTitle; 72349e4fd71Sdrh extern int sqlite3MemdebugSettitle(const char*); 724*a359b5eeSmistachkin zTitle = Tcl_GetString(objv[1]); 72549e4fd71Sdrh sqlite3MemdebugSettitle(zTitle); 7264a50aac5Sdrh } 7274a50aac5Sdrh #endif 7284a50aac5Sdrh return TCL_OK; 7294a50aac5Sdrh } 7304a50aac5Sdrh 731cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES 10 732ec561a35Sdan #define MALLOC_LOG_KEYINTS ( \ 733ec561a35Sdan 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \ 734ec561a35Sdan ) 7356f332c18Sdanielk1977 static Tcl_HashTable aMallocLog; 7366f332c18Sdanielk1977 static int mallocLogEnabled = 0; 7376f332c18Sdanielk1977 7386f332c18Sdanielk1977 typedef struct MallocLog MallocLog; 7396f332c18Sdanielk1977 struct MallocLog { 7406f332c18Sdanielk1977 int nCall; 7416f332c18Sdanielk1977 int nByte; 7426f332c18Sdanielk1977 }; 7436f332c18Sdanielk1977 744afdd23a4Sshane #ifdef SQLITE_MEMDEBUG 7456f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ 7466f332c18Sdanielk1977 if( mallocLogEnabled ){ 7476f332c18Sdanielk1977 MallocLog *pLog; 7486f332c18Sdanielk1977 Tcl_HashEntry *pEntry; 7496f332c18Sdanielk1977 int isNew; 7506f332c18Sdanielk1977 751ec561a35Sdan int aKey[MALLOC_LOG_KEYINTS]; 752ec561a35Sdan int nKey = sizeof(int)*MALLOC_LOG_KEYINTS; 7536f332c18Sdanielk1977 7546f332c18Sdanielk1977 memset(aKey, 0, nKey); 7556f332c18Sdanielk1977 if( (sizeof(void*)*nFrame)<nKey ){ 7566f332c18Sdanielk1977 nKey = nFrame*sizeof(void*); 7576f332c18Sdanielk1977 } 7586f332c18Sdanielk1977 memcpy(aKey, aFrame, nKey); 7596f332c18Sdanielk1977 7606f332c18Sdanielk1977 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); 7616f332c18Sdanielk1977 if( isNew ){ 7626f332c18Sdanielk1977 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); 7636f332c18Sdanielk1977 memset(pLog, 0, sizeof(MallocLog)); 7646f332c18Sdanielk1977 Tcl_SetHashValue(pEntry, (ClientData)pLog); 7656f332c18Sdanielk1977 }else{ 7666f332c18Sdanielk1977 pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 7676f332c18Sdanielk1977 } 7686f332c18Sdanielk1977 7696f332c18Sdanielk1977 pLog->nCall++; 7706f332c18Sdanielk1977 pLog->nByte += nByte; 7716f332c18Sdanielk1977 } 7726f332c18Sdanielk1977 } 773afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */ 7746f332c18Sdanielk1977 77564aca191Sdanielk1977 static void test_memdebug_log_clear(void){ 776dbdc4d49Sdanielk1977 Tcl_HashSearch search; 777dbdc4d49Sdanielk1977 Tcl_HashEntry *pEntry; 778dbdc4d49Sdanielk1977 for( 779dbdc4d49Sdanielk1977 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 780dbdc4d49Sdanielk1977 pEntry; 781dbdc4d49Sdanielk1977 pEntry=Tcl_NextHashEntry(&search) 782dbdc4d49Sdanielk1977 ){ 783dbdc4d49Sdanielk1977 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 784dbdc4d49Sdanielk1977 Tcl_Free((char *)pLog); 785dbdc4d49Sdanielk1977 } 786dbdc4d49Sdanielk1977 Tcl_DeleteHashTable(&aMallocLog); 787ec561a35Sdan Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS); 788dbdc4d49Sdanielk1977 } 789dbdc4d49Sdanielk1977 7906f332c18Sdanielk1977 static int test_memdebug_log( 7916f332c18Sdanielk1977 void * clientData, 7926f332c18Sdanielk1977 Tcl_Interp *interp, 7936f332c18Sdanielk1977 int objc, 7946f332c18Sdanielk1977 Tcl_Obj *CONST objv[] 7956f332c18Sdanielk1977 ){ 7966f332c18Sdanielk1977 static int isInit = 0; 7976f332c18Sdanielk1977 int iSub; 7986f332c18Sdanielk1977 799dbdc4d49Sdanielk1977 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" }; 800dbdc4d49Sdanielk1977 enum MB_enum { 801dbdc4d49Sdanielk1977 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC 802dbdc4d49Sdanielk1977 }; 8036f332c18Sdanielk1977 8046f332c18Sdanielk1977 if( !isInit ){ 8056f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG 8066f332c18Sdanielk1977 extern void sqlite3MemdebugBacktraceCallback( 8076f332c18Sdanielk1977 void (*xBacktrace)(int, int, void **)); 8086f332c18Sdanielk1977 sqlite3MemdebugBacktraceCallback(test_memdebug_callback); 8096f332c18Sdanielk1977 #endif 810ec561a35Sdan Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS); 8116f332c18Sdanielk1977 isInit = 1; 8126f332c18Sdanielk1977 } 8136f332c18Sdanielk1977 8146f332c18Sdanielk1977 if( objc<2 ){ 8156f332c18Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 8166f332c18Sdanielk1977 } 8176f332c18Sdanielk1977 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ 8186f332c18Sdanielk1977 return TCL_ERROR; 8196f332c18Sdanielk1977 } 8206f332c18Sdanielk1977 8216f332c18Sdanielk1977 switch( (enum MB_enum)iSub ){ 8226f332c18Sdanielk1977 case MB_LOG_START: 8236f332c18Sdanielk1977 mallocLogEnabled = 1; 8246f332c18Sdanielk1977 break; 8256f332c18Sdanielk1977 case MB_LOG_STOP: 8266f332c18Sdanielk1977 mallocLogEnabled = 0; 8276f332c18Sdanielk1977 break; 8286f332c18Sdanielk1977 case MB_LOG_DUMP: { 8296f332c18Sdanielk1977 Tcl_HashSearch search; 8306f332c18Sdanielk1977 Tcl_HashEntry *pEntry; 8316f332c18Sdanielk1977 Tcl_Obj *pRet = Tcl_NewObj(); 8326f332c18Sdanielk1977 833ec561a35Sdan assert(sizeof(Tcl_WideInt)>=sizeof(void*)); 8346f332c18Sdanielk1977 8356f332c18Sdanielk1977 for( 8366f332c18Sdanielk1977 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 8376f332c18Sdanielk1977 pEntry; 8386f332c18Sdanielk1977 pEntry=Tcl_NextHashEntry(&search) 8396f332c18Sdanielk1977 ){ 8406f332c18Sdanielk1977 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; 8416f332c18Sdanielk1977 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 842ec561a35Sdan Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry); 8436f332c18Sdanielk1977 int ii; 8446f332c18Sdanielk1977 8456f332c18Sdanielk1977 apElem[0] = Tcl_NewIntObj(pLog->nCall); 8466f332c18Sdanielk1977 apElem[1] = Tcl_NewIntObj(pLog->nByte); 8476f332c18Sdanielk1977 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ 848ec561a35Sdan apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]); 8496f332c18Sdanielk1977 } 8506f332c18Sdanielk1977 8516f332c18Sdanielk1977 Tcl_ListObjAppendElement(interp, pRet, 8526f332c18Sdanielk1977 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) 8536f332c18Sdanielk1977 ); 8546f332c18Sdanielk1977 } 8556f332c18Sdanielk1977 8566f332c18Sdanielk1977 Tcl_SetObjResult(interp, pRet); 8576f332c18Sdanielk1977 break; 8586f332c18Sdanielk1977 } 8596f332c18Sdanielk1977 case MB_LOG_CLEAR: { 860dbdc4d49Sdanielk1977 test_memdebug_log_clear(); 861dbdc4d49Sdanielk1977 break; 8626f332c18Sdanielk1977 } 863dbdc4d49Sdanielk1977 864dbdc4d49Sdanielk1977 case MB_LOG_SYNC: { 865b940492eSdrh #ifdef SQLITE_MEMDEBUG 866dbdc4d49Sdanielk1977 extern void sqlite3MemdebugSync(); 867dbdc4d49Sdanielk1977 test_memdebug_log_clear(); 868dbdc4d49Sdanielk1977 mallocLogEnabled = 1; 869dbdc4d49Sdanielk1977 sqlite3MemdebugSync(); 870b940492eSdrh #endif 871dbdc4d49Sdanielk1977 break; 8726f332c18Sdanielk1977 } 8736f332c18Sdanielk1977 } 8746f332c18Sdanielk1977 8756f332c18Sdanielk1977 return TCL_OK; 8766f332c18Sdanielk1977 } 8774a50aac5Sdrh 8784a50aac5Sdrh /* 8799ac3fe97Sdrh ** Usage: sqlite3_config_scratch SIZE N 8809ac3fe97Sdrh ** 8819ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. 8829ac3fe97Sdrh ** The buffer is static and is of limited size. N might be 8839ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size. 8849ac3fe97Sdrh ** The revised value of N is returned. 8859ac3fe97Sdrh ** 8869ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL. 8879ac3fe97Sdrh */ 8889ac3fe97Sdrh static int test_config_scratch( 8899ac3fe97Sdrh void * clientData, 8909ac3fe97Sdrh Tcl_Interp *interp, 8919ac3fe97Sdrh int objc, 8929ac3fe97Sdrh Tcl_Obj *CONST objv[] 8939ac3fe97Sdrh ){ 8949ac3fe97Sdrh int sz, N, rc; 8959ac3fe97Sdrh Tcl_Obj *pResult; 8965f4bcf15Sdrh static char *buf = 0; 8979ac3fe97Sdrh if( objc!=3 ){ 8989ac3fe97Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 8999ac3fe97Sdrh return TCL_ERROR; 9009ac3fe97Sdrh } 901f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 902f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 9035f4bcf15Sdrh free(buf); 9049ac3fe97Sdrh if( sz<0 ){ 9055f4bcf15Sdrh buf = 0; 9069ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); 907f7141990Sdrh }else{ 9086480aad4Sdrh buf = malloc( sz*N + 1 ); 9099ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); 9109ac3fe97Sdrh } 9119ac3fe97Sdrh pResult = Tcl_NewObj(); 9129ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 9139ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 9149ac3fe97Sdrh Tcl_SetObjResult(interp, pResult); 9159ac3fe97Sdrh return TCL_OK; 9169ac3fe97Sdrh } 9179ac3fe97Sdrh 9189ac3fe97Sdrh /* 9199ac3fe97Sdrh ** Usage: sqlite3_config_pagecache SIZE N 9209ac3fe97Sdrh ** 9219ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. 9229ac3fe97Sdrh ** The buffer is static and is of limited size. N might be 9239ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size. 9249ac3fe97Sdrh ** The revised value of N is returned. 9259ac3fe97Sdrh ** 9269ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL. 9279ac3fe97Sdrh */ 9289ac3fe97Sdrh static int test_config_pagecache( 9299ac3fe97Sdrh void * clientData, 9309ac3fe97Sdrh Tcl_Interp *interp, 9319ac3fe97Sdrh int objc, 9329ac3fe97Sdrh Tcl_Obj *CONST objv[] 9339ac3fe97Sdrh ){ 9349ac3fe97Sdrh int sz, N, rc; 9359ac3fe97Sdrh Tcl_Obj *pResult; 9365f4bcf15Sdrh static char *buf = 0; 9379ac3fe97Sdrh if( objc!=3 ){ 9389ac3fe97Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 9399ac3fe97Sdrh return TCL_ERROR; 9409ac3fe97Sdrh } 941f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 942f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 9435f4bcf15Sdrh free(buf); 9449ac3fe97Sdrh if( sz<0 ){ 9455f4bcf15Sdrh buf = 0; 946f7141990Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); 947f7141990Sdrh }else{ 9480a60a384Sdrh buf = malloc( sz*N ); 9499ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); 9509ac3fe97Sdrh } 9519ac3fe97Sdrh pResult = Tcl_NewObj(); 9529ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 9539ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 9549ac3fe97Sdrh Tcl_SetObjResult(interp, pResult); 9559ac3fe97Sdrh return TCL_OK; 9569ac3fe97Sdrh } 9579ac3fe97Sdrh 958f7141990Sdrh /* 959b232c232Sdrh ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED 960b232c232Sdrh ** 961b232c232Sdrh ** Set up the alternative test page cache. Install if INSTALL_FLAG is 962b232c232Sdrh ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG 963b232c232Sdrh ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive 964b232c232Sdrh ** which determines the chance of discarding a page when unpinned. 100 965b232c232Sdrh ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator 966b232c232Sdrh ** seed. 967b232c232Sdrh */ 968b232c232Sdrh static int test_alt_pcache( 969b232c232Sdrh void * clientData, 970b232c232Sdrh Tcl_Interp *interp, 971b232c232Sdrh int objc, 972b232c232Sdrh Tcl_Obj *CONST objv[] 973b232c232Sdrh ){ 974b232c232Sdrh int installFlag; 975f2a84e3cSdrh int discardChance = 0; 976f2a84e3cSdrh int prngSeed = 0; 977f2a84e3cSdrh int highStress = 0; 978f2a84e3cSdrh extern void installTestPCache(int,unsigned,unsigned,unsigned); 979f2a84e3cSdrh if( objc<2 || objc>5 ){ 980f2a84e3cSdrh Tcl_WrongNumArgs(interp, 1, objv, 981f2a84e3cSdrh "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS"); 982b232c232Sdrh return TCL_ERROR; 983b232c232Sdrh } 984b232c232Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR; 985f2a84e3cSdrh if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){ 986f2a84e3cSdrh return TCL_ERROR; 987f2a84e3cSdrh } 988f2a84e3cSdrh if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){ 989f2a84e3cSdrh return TCL_ERROR; 990f2a84e3cSdrh } 991f2a84e3cSdrh if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){ 992f2a84e3cSdrh return TCL_ERROR; 993f2a84e3cSdrh } 994b232c232Sdrh if( discardChance<0 || discardChance>100 ){ 995b232c232Sdrh Tcl_AppendResult(interp, "discard-chance should be between 0 and 100", 996b232c232Sdrh (char*)0); 997b232c232Sdrh return TCL_ERROR; 998b232c232Sdrh } 999f2a84e3cSdrh installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed, 1000f2a84e3cSdrh (unsigned)highStress); 1001b232c232Sdrh return TCL_OK; 1002b232c232Sdrh } 1003b232c232Sdrh 1004b232c232Sdrh /* 10058a42cbd3Sdrh ** Usage: sqlite3_config_memstatus BOOLEAN 10068a42cbd3Sdrh ** 10078a42cbd3Sdrh ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. 10088a42cbd3Sdrh */ 10098a42cbd3Sdrh static int test_config_memstatus( 10108a42cbd3Sdrh void * clientData, 10118a42cbd3Sdrh Tcl_Interp *interp, 10128a42cbd3Sdrh int objc, 10138a42cbd3Sdrh Tcl_Obj *CONST objv[] 10148a42cbd3Sdrh ){ 10158a42cbd3Sdrh int enable, rc; 10168a42cbd3Sdrh if( objc!=2 ){ 10178a42cbd3Sdrh Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 10188a42cbd3Sdrh return TCL_ERROR; 10198a42cbd3Sdrh } 10208a42cbd3Sdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR; 10218a42cbd3Sdrh rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable); 10228a42cbd3Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 10238a42cbd3Sdrh return TCL_OK; 10248a42cbd3Sdrh } 10258a42cbd3Sdrh 10268a42cbd3Sdrh /* 1027633e6d57Sdrh ** Usage: sqlite3_config_lookaside SIZE COUNT 1028633e6d57Sdrh ** 1029633e6d57Sdrh */ 1030633e6d57Sdrh static int test_config_lookaside( 1031633e6d57Sdrh void * clientData, 1032633e6d57Sdrh Tcl_Interp *interp, 1033633e6d57Sdrh int objc, 1034633e6d57Sdrh Tcl_Obj *CONST objv[] 1035633e6d57Sdrh ){ 1036633e6d57Sdrh int sz, cnt; 1037ab7bee89Sdanielk1977 Tcl_Obj *pRet; 1038633e6d57Sdrh if( objc!=3 ){ 1039633e6d57Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT"); 1040633e6d57Sdrh return TCL_ERROR; 1041633e6d57Sdrh } 1042633e6d57Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 1043633e6d57Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR; 1044ab7bee89Sdanielk1977 pRet = Tcl_NewObj(); 1045ab7bee89Sdanielk1977 Tcl_ListObjAppendElement( 1046ab7bee89Sdanielk1977 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside) 1047ab7bee89Sdanielk1977 ); 1048ab7bee89Sdanielk1977 Tcl_ListObjAppendElement( 1049ab7bee89Sdanielk1977 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside) 1050ab7bee89Sdanielk1977 ); 1051caffb1a5Sdrh sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt); 1052ab7bee89Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1053633e6d57Sdrh return TCL_OK; 1054633e6d57Sdrh } 1055633e6d57Sdrh 1056633e6d57Sdrh 1057633e6d57Sdrh /* 1058e9d1c720Sdrh ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT 1059633e6d57Sdrh ** 1060e9d1c720Sdrh ** There are two static buffers with BUFID 1 and 2. Each static buffer 1061e9d1c720Sdrh ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL 1062e9d1c720Sdrh ** which will cause sqlite3_db_config() to allocate space on its own. 1063633e6d57Sdrh */ 1064633e6d57Sdrh static int test_db_config_lookaside( 1065633e6d57Sdrh void * clientData, 1066633e6d57Sdrh Tcl_Interp *interp, 1067633e6d57Sdrh int objc, 1068633e6d57Sdrh Tcl_Obj *CONST objv[] 1069633e6d57Sdrh ){ 1070633e6d57Sdrh int rc; 1071633e6d57Sdrh int sz, cnt; 1072633e6d57Sdrh sqlite3 *db; 1073e9d1c720Sdrh int bufid; 1074e9d1c720Sdrh static char azBuf[2][10000]; 1075633e6d57Sdrh int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1076e9d1c720Sdrh if( objc!=5 ){ 1077e9d1c720Sdrh Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT"); 1078633e6d57Sdrh return TCL_ERROR; 1079633e6d57Sdrh } 1080633e6d57Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1081e9d1c720Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR; 1082e9d1c720Sdrh if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR; 1083e9d1c720Sdrh if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR; 1084e9d1c720Sdrh if( bufid==0 ){ 1085e9d1c720Sdrh rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt); 1086e9d1c720Sdrh }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){ 1087e9d1c720Sdrh rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt); 1088e9d1c720Sdrh }else{ 1089e9d1c720Sdrh Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0); 1090e9d1c720Sdrh return TCL_ERROR; 1091e9d1c720Sdrh } 1092633e6d57Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 1093633e6d57Sdrh return TCL_OK; 1094633e6d57Sdrh } 1095633e6d57Sdrh 1096633e6d57Sdrh /* 10978765b466Smistachkin ** Usage: sqlite3_config_heap NBYTE NMINALLOC 10985099be5eSdanielk1977 */ 10995099be5eSdanielk1977 static int test_config_heap( 11005099be5eSdanielk1977 void * clientData, 11015099be5eSdanielk1977 Tcl_Interp *interp, 11025099be5eSdanielk1977 int objc, 11035099be5eSdanielk1977 Tcl_Obj *CONST objv[] 11045099be5eSdanielk1977 ){ 11057830cd41Sdrh static char *zBuf; /* Use this memory */ 11065099be5eSdanielk1977 int nByte; /* Size of buffer to pass to sqlite3_config() */ 11075099be5eSdanielk1977 int nMinAlloc; /* Size of minimum allocation */ 11085099be5eSdanielk1977 int rc; /* Return code of sqlite3_config() */ 11095099be5eSdanielk1977 11105099be5eSdanielk1977 Tcl_Obj * CONST *aArg = &objv[1]; 11115099be5eSdanielk1977 int nArg = objc-1; 11125099be5eSdanielk1977 11135099be5eSdanielk1977 if( nArg!=2 ){ 11148a42cbd3Sdrh Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC"); 11155099be5eSdanielk1977 return TCL_ERROR; 11165099be5eSdanielk1977 } 11175099be5eSdanielk1977 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR; 11185099be5eSdanielk1977 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR; 11195099be5eSdanielk1977 11200d84e5b2Sdanielk1977 if( nByte==0 ){ 11217830cd41Sdrh free( zBuf ); 11227830cd41Sdrh zBuf = 0; 11238a42cbd3Sdrh rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); 11240d84e5b2Sdanielk1977 }else{ 11257830cd41Sdrh zBuf = realloc(zBuf, nByte); 11265099be5eSdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); 11270d84e5b2Sdanielk1977 } 11285099be5eSdanielk1977 11295099be5eSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 11305099be5eSdanielk1977 return TCL_OK; 11315099be5eSdanielk1977 } 11325099be5eSdanielk1977 11335099be5eSdanielk1977 /* 11348765b466Smistachkin ** Usage: sqlite3_config_error [DB] 11356480aad4Sdrh ** 11366480aad4Sdrh ** Invoke sqlite3_config() or sqlite3_db_config() with invalid 11376480aad4Sdrh ** opcodes and verify that they return errors. 11386480aad4Sdrh */ 11396480aad4Sdrh static int test_config_error( 11406480aad4Sdrh void * clientData, 11416480aad4Sdrh Tcl_Interp *interp, 11426480aad4Sdrh int objc, 11436480aad4Sdrh Tcl_Obj *CONST objv[] 11446480aad4Sdrh ){ 11456480aad4Sdrh sqlite3 *db; 11466480aad4Sdrh int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 11476480aad4Sdrh 11486480aad4Sdrh if( objc!=2 && objc!=1 ){ 11496480aad4Sdrh Tcl_WrongNumArgs(interp, 1, objv, "[DB]"); 11506480aad4Sdrh return TCL_ERROR; 11516480aad4Sdrh } 11526480aad4Sdrh if( objc==2 ){ 11536480aad4Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11546480aad4Sdrh if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){ 11556480aad4Sdrh Tcl_AppendResult(interp, 11566480aad4Sdrh "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR", 11576480aad4Sdrh (char*)0); 11586480aad4Sdrh return TCL_ERROR; 11596480aad4Sdrh } 11606480aad4Sdrh }else{ 11616480aad4Sdrh if( sqlite3_config(99999)!=SQLITE_ERROR ){ 11626480aad4Sdrh Tcl_AppendResult(interp, 11636480aad4Sdrh "sqlite3_config(99999) does not return SQLITE_ERROR", 11646480aad4Sdrh (char*)0); 11656480aad4Sdrh return TCL_ERROR; 11666480aad4Sdrh } 11676480aad4Sdrh } 11686480aad4Sdrh return TCL_OK; 11696480aad4Sdrh } 11706480aad4Sdrh 11716480aad4Sdrh /* 11728765b466Smistachkin ** Usage: sqlite3_config_uri BOOLEAN 1173cd74b611Sdan ** 11748765b466Smistachkin ** Enables or disables interpretation of URI parameters by default using 11758765b466Smistachkin ** SQLITE_CONFIG_URI. 1176cd74b611Sdan */ 1177cd74b611Sdan static int test_config_uri( 1178cd74b611Sdan void * clientData, 1179cd74b611Sdan Tcl_Interp *interp, 1180cd74b611Sdan int objc, 1181cd74b611Sdan Tcl_Obj *CONST objv[] 1182cd74b611Sdan ){ 1183cd74b611Sdan int rc; 1184cd74b611Sdan int bOpenUri; 1185cd74b611Sdan 1186cd74b611Sdan if( objc!=2 ){ 1187cd74b611Sdan Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); 1188cd74b611Sdan return TCL_ERROR; 1189cd74b611Sdan } 1190cd74b611Sdan if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){ 1191cd74b611Sdan return TCL_ERROR; 1192cd74b611Sdan } 1193cd74b611Sdan 1194cd74b611Sdan rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri); 1195cd74b611Sdan Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1196cd74b611Sdan 1197cd74b611Sdan return TCL_OK; 1198cd74b611Sdan } 1199cd74b611Sdan 1200cd74b611Sdan /* 1201de9a7b8aSdrh ** Usage: sqlite3_config_cis BOOLEAN 1202de9a7b8aSdrh ** 1203de9a7b8aSdrh ** Enables or disables the use of the covering-index scan optimization. 1204de9a7b8aSdrh ** SQLITE_CONFIG_COVERING_INDEX_SCAN. 1205de9a7b8aSdrh */ 1206de9a7b8aSdrh static int test_config_cis( 1207de9a7b8aSdrh void * clientData, 1208de9a7b8aSdrh Tcl_Interp *interp, 1209de9a7b8aSdrh int objc, 1210de9a7b8aSdrh Tcl_Obj *CONST objv[] 1211de9a7b8aSdrh ){ 1212de9a7b8aSdrh int rc; 1213de9a7b8aSdrh int bUseCis; 1214de9a7b8aSdrh 1215de9a7b8aSdrh if( objc!=2 ){ 1216de9a7b8aSdrh Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); 1217de9a7b8aSdrh return TCL_ERROR; 1218de9a7b8aSdrh } 1219de9a7b8aSdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){ 1220de9a7b8aSdrh return TCL_ERROR; 1221de9a7b8aSdrh } 1222de9a7b8aSdrh 1223de9a7b8aSdrh rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis); 1224de9a7b8aSdrh Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1225de9a7b8aSdrh 1226de9a7b8aSdrh return TCL_OK; 1227de9a7b8aSdrh } 1228de9a7b8aSdrh 1229de9a7b8aSdrh /* 12308765b466Smistachkin ** Usage: sqlite3_dump_memsys3 FILENAME 1231c66c0e14Sdanielk1977 ** sqlite3_dump_memsys5 FILENAME 123232155ef0Sdanielk1977 ** 123332155ef0Sdanielk1977 ** Write a summary of unfreed memsys3 allocations to FILENAME. 123432155ef0Sdanielk1977 */ 123532155ef0Sdanielk1977 static int test_dump_memsys3( 123632155ef0Sdanielk1977 void * clientData, 123732155ef0Sdanielk1977 Tcl_Interp *interp, 123832155ef0Sdanielk1977 int objc, 123932155ef0Sdanielk1977 Tcl_Obj *CONST objv[] 124032155ef0Sdanielk1977 ){ 124132155ef0Sdanielk1977 if( objc!=2 ){ 124232155ef0Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 124332155ef0Sdanielk1977 return TCL_ERROR; 124432155ef0Sdanielk1977 } 1245c66c0e14Sdanielk1977 1246860e332cSdrh switch( SQLITE_PTR_TO_INT(clientData) ){ 12470d84e5b2Sdanielk1977 case 3: { 1248c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS3 124932155ef0Sdanielk1977 extern void sqlite3Memsys3Dump(const char*); 125032155ef0Sdanielk1977 sqlite3Memsys3Dump(Tcl_GetString(objv[1])); 1251c66c0e14Sdanielk1977 break; 125232155ef0Sdanielk1977 #endif 1253c66c0e14Sdanielk1977 } 12540d84e5b2Sdanielk1977 case 5: { 1255c66c0e14Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS5 1256c66c0e14Sdanielk1977 extern void sqlite3Memsys5Dump(const char*); 1257c66c0e14Sdanielk1977 sqlite3Memsys5Dump(Tcl_GetString(objv[1])); 1258c66c0e14Sdanielk1977 break; 1259c66c0e14Sdanielk1977 #endif 1260c66c0e14Sdanielk1977 } 1261c66c0e14Sdanielk1977 } 126232155ef0Sdanielk1977 return TCL_OK; 126332155ef0Sdanielk1977 } 126432155ef0Sdanielk1977 126532155ef0Sdanielk1977 /* 1266f7141990Sdrh ** Usage: sqlite3_status OPCODE RESETFLAG 1267f7141990Sdrh ** 1268f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return 1269f7141990Sdrh ** code, the current value, and the high-water mark value. 1270f7141990Sdrh */ 1271f7141990Sdrh static int test_status( 1272f7141990Sdrh void * clientData, 1273f7141990Sdrh Tcl_Interp *interp, 1274f7141990Sdrh int objc, 1275f7141990Sdrh Tcl_Obj *CONST objv[] 1276f7141990Sdrh ){ 1277f7141990Sdrh int rc, iValue, mxValue; 1278f7141990Sdrh int i, op, resetFlag; 1279f7141990Sdrh const char *zOpName; 1280f7141990Sdrh static const struct { 1281f7141990Sdrh const char *zName; 1282f7141990Sdrh int op; 1283f7141990Sdrh } aOp[] = { 1284f7141990Sdrh { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, 1285e50135e2Sdrh { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, 1286f7141990Sdrh { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, 1287f7141990Sdrh { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, 1288e50135e2Sdrh { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE }, 1289f7141990Sdrh { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, 1290f7141990Sdrh { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, 1291e50135e2Sdrh { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE }, 1292ec424a5bSdrh { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK }, 1293eafc43b1Sdrh { "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT }, 1294f7141990Sdrh }; 1295f7141990Sdrh Tcl_Obj *pResult; 1296f7141990Sdrh if( objc!=3 ){ 1297f7141990Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1298f7141990Sdrh return TCL_ERROR; 1299f7141990Sdrh } 1300f7141990Sdrh zOpName = Tcl_GetString(objv[1]); 1301f7141990Sdrh for(i=0; i<ArraySize(aOp); i++){ 1302f7141990Sdrh if( strcmp(aOp[i].zName, zOpName)==0 ){ 1303f7141990Sdrh op = aOp[i].op; 1304f7141990Sdrh break; 1305f7141990Sdrh } 1306f7141990Sdrh } 1307f7141990Sdrh if( i>=ArraySize(aOp) ){ 1308f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; 1309f7141990Sdrh } 1310f7141990Sdrh if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; 1311af005fbcSdrh iValue = 0; 1312af005fbcSdrh mxValue = 0; 1313f7141990Sdrh rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); 1314f7141990Sdrh pResult = Tcl_NewObj(); 1315f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1316f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1317f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1318f7141990Sdrh Tcl_SetObjResult(interp, pResult); 1319f7141990Sdrh return TCL_OK; 1320f7141990Sdrh } 13219ac3fe97Sdrh 13229ac3fe97Sdrh /* 1323633e6d57Sdrh ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG 1324633e6d57Sdrh ** 1325633e6d57Sdrh ** Return a list of three elements which are the sqlite3_db_status() return 1326633e6d57Sdrh ** code, the current value, and the high-water mark value. 1327633e6d57Sdrh */ 1328633e6d57Sdrh static int test_db_status( 1329633e6d57Sdrh void * clientData, 1330633e6d57Sdrh Tcl_Interp *interp, 1331633e6d57Sdrh int objc, 1332633e6d57Sdrh Tcl_Obj *CONST objv[] 1333633e6d57Sdrh ){ 1334633e6d57Sdrh int rc, iValue, mxValue; 1335633e6d57Sdrh int i, op, resetFlag; 1336633e6d57Sdrh const char *zOpName; 1337633e6d57Sdrh sqlite3 *db; 1338633e6d57Sdrh int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1339633e6d57Sdrh static const struct { 1340633e6d57Sdrh const char *zName; 1341633e6d57Sdrh int op; 1342633e6d57Sdrh } aOp[] = { 13432a58e9ccSdrh { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, 13442a58e9ccSdrh { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED }, 13452a58e9ccSdrh { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED }, 13462a58e9ccSdrh { "STMT_USED", SQLITE_DBSTATUS_STMT_USED }, 13472a58e9ccSdrh { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT }, 13482a58e9ccSdrh { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE }, 134958ca31c9Sdan { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }, 135058ca31c9Sdan { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT }, 13519ad3ee40Sdrh { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS }, 13529ad3ee40Sdrh { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE } 1353633e6d57Sdrh }; 1354633e6d57Sdrh Tcl_Obj *pResult; 1355633e6d57Sdrh if( objc!=4 ){ 135658ca31c9Sdan Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG"); 1357633e6d57Sdrh return TCL_ERROR; 1358633e6d57Sdrh } 1359633e6d57Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1360633e6d57Sdrh zOpName = Tcl_GetString(objv[2]); 13612a58e9ccSdrh if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7; 13622a58e9ccSdrh if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9; 1363633e6d57Sdrh for(i=0; i<ArraySize(aOp); i++){ 1364633e6d57Sdrh if( strcmp(aOp[i].zName, zOpName)==0 ){ 1365633e6d57Sdrh op = aOp[i].op; 1366633e6d57Sdrh break; 1367633e6d57Sdrh } 1368633e6d57Sdrh } 1369633e6d57Sdrh if( i>=ArraySize(aOp) ){ 1370633e6d57Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR; 1371633e6d57Sdrh } 1372633e6d57Sdrh if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR; 1373633e6d57Sdrh iValue = 0; 1374633e6d57Sdrh mxValue = 0; 1375633e6d57Sdrh rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag); 1376633e6d57Sdrh pResult = Tcl_NewObj(); 1377633e6d57Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1378633e6d57Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1379633e6d57Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1380633e6d57Sdrh Tcl_SetObjResult(interp, pResult); 1381633e6d57Sdrh return TCL_OK; 1382633e6d57Sdrh } 1383633e6d57Sdrh 1384633e6d57Sdrh /* 1385d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN 1386d09414cdSdanielk1977 */ 1387d09414cdSdanielk1977 static int test_install_malloc_faultsim( 1388d09414cdSdanielk1977 void * clientData, 1389d09414cdSdanielk1977 Tcl_Interp *interp, 1390d09414cdSdanielk1977 int objc, 1391d09414cdSdanielk1977 Tcl_Obj *CONST objv[] 1392d09414cdSdanielk1977 ){ 1393d09414cdSdanielk1977 int rc; 1394d09414cdSdanielk1977 int isInstall; 1395d09414cdSdanielk1977 1396d09414cdSdanielk1977 if( objc!=2 ){ 1397d09414cdSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 1398d09414cdSdanielk1977 return TCL_ERROR; 1399d09414cdSdanielk1977 } 1400d09414cdSdanielk1977 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 1401d09414cdSdanielk1977 return TCL_ERROR; 1402d09414cdSdanielk1977 } 1403ef05f2dfSdanielk1977 rc = faultsimInstall(isInstall); 1404d09414cdSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1405d09414cdSdanielk1977 return TCL_OK; 1406d09414cdSdanielk1977 } 1407d09414cdSdanielk1977 1408d09414cdSdanielk1977 /* 14098b322827Sdanielk1977 ** sqlite3_install_memsys3 14108b322827Sdanielk1977 */ 14118b322827Sdanielk1977 static int test_install_memsys3( 14128b322827Sdanielk1977 void * clientData, 14138b322827Sdanielk1977 Tcl_Interp *interp, 14148b322827Sdanielk1977 int objc, 14158b322827Sdanielk1977 Tcl_Obj *CONST objv[] 14168b322827Sdanielk1977 ){ 14178b322827Sdanielk1977 int rc = SQLITE_MISUSE; 14188b322827Sdanielk1977 #ifdef SQLITE_ENABLE_MEMSYS3 14198b322827Sdanielk1977 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); 14208b322827Sdanielk1977 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3()); 14218b322827Sdanielk1977 #endif 14228b322827Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 14238b322827Sdanielk1977 return TCL_OK; 14248b322827Sdanielk1977 } 14258b322827Sdanielk1977 1426c396d4afSdan static int test_vfs_oom_test( 1427c396d4afSdan void * clientData, 1428c396d4afSdan Tcl_Interp *interp, 1429c396d4afSdan int objc, 1430c396d4afSdan Tcl_Obj *CONST objv[] 1431c396d4afSdan ){ 1432c396d4afSdan extern int sqlite3_memdebug_vfs_oom_test; 1433c396d4afSdan if( objc>2 ){ 1434c396d4afSdan Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?"); 1435c396d4afSdan return TCL_ERROR; 1436c396d4afSdan }else if( objc==2 ){ 1437c396d4afSdan int iNew; 1438c396d4afSdan if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR; 1439c396d4afSdan sqlite3_memdebug_vfs_oom_test = iNew; 1440c396d4afSdan } 1441c396d4afSdan Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test)); 1442c396d4afSdan return TCL_OK; 1443c396d4afSdan } 1444c396d4afSdan 14458b322827Sdanielk1977 /* 14462f999a67Sdrh ** Register commands with the TCL interpreter. 14472f999a67Sdrh */ 14482f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 14492f999a67Sdrh static struct { 14502f999a67Sdrh char *zName; 14512f999a67Sdrh Tcl_ObjCmdProc *xProc; 1452c66c0e14Sdanielk1977 int clientData; 14532f999a67Sdrh } aObjCmd[] = { 14548a42cbd3Sdrh { "sqlite3_malloc", test_malloc ,0 }, 14558a42cbd3Sdrh { "sqlite3_realloc", test_realloc ,0 }, 14568a42cbd3Sdrh { "sqlite3_free", test_free ,0 }, 14578a42cbd3Sdrh { "memset", test_memset ,0 }, 14588a42cbd3Sdrh { "memget", test_memget ,0 }, 14598a42cbd3Sdrh { "sqlite3_memory_used", test_memory_used ,0 }, 14608a42cbd3Sdrh { "sqlite3_memory_highwater", test_memory_highwater ,0 }, 14618a42cbd3Sdrh { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 }, 14628a42cbd3Sdrh { "sqlite3_memdebug_dump", test_memdebug_dump ,0 }, 14638a42cbd3Sdrh { "sqlite3_memdebug_fail", test_memdebug_fail ,0 }, 14648a42cbd3Sdrh { "sqlite3_memdebug_pending", test_memdebug_pending ,0 }, 14658a42cbd3Sdrh { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 }, 14668a42cbd3Sdrh { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 }, 14678a42cbd3Sdrh { "sqlite3_memdebug_log", test_memdebug_log ,0 }, 14688a42cbd3Sdrh { "sqlite3_config_scratch", test_config_scratch ,0 }, 14698a42cbd3Sdrh { "sqlite3_config_pagecache", test_config_pagecache ,0 }, 1470b232c232Sdrh { "sqlite3_config_alt_pcache", test_alt_pcache ,0 }, 14718a42cbd3Sdrh { "sqlite3_status", test_status ,0 }, 1472633e6d57Sdrh { "sqlite3_db_status", test_db_status ,0 }, 14738a42cbd3Sdrh { "install_malloc_faultsim", test_install_malloc_faultsim ,0 }, 14745099be5eSdanielk1977 { "sqlite3_config_heap", test_config_heap ,0 }, 14758a42cbd3Sdrh { "sqlite3_config_memstatus", test_config_memstatus ,0 }, 1476633e6d57Sdrh { "sqlite3_config_lookaside", test_config_lookaside ,0 }, 14776480aad4Sdrh { "sqlite3_config_error", test_config_error ,0 }, 1478cd74b611Sdan { "sqlite3_config_uri", test_config_uri ,0 }, 1479de9a7b8aSdrh { "sqlite3_config_cis", test_config_cis ,0 }, 1480633e6d57Sdrh { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, 14810d84e5b2Sdanielk1977 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, 1482b232c232Sdrh { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, 14838b322827Sdanielk1977 { "sqlite3_install_memsys3", test_install_memsys3 ,0 }, 1484c396d4afSdan { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 }, 14852f999a67Sdrh }; 14862f999a67Sdrh int i; 14872f999a67Sdrh for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 1488860e332cSdrh ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData); 1489c66c0e14Sdanielk1977 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); 14902f999a67Sdrh } 14912f999a67Sdrh return TCL_OK; 14922f999a67Sdrh } 1493ef05f2dfSdanielk1977 #endif 1494