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*d09414cdSdanielk1977 ** $Id: test_malloc.c,v 1.26 2008/06/19 18:17:50 danielk1977 Exp $ 172f999a67Sdrh */ 182f999a67Sdrh #include "sqliteInt.h" 192f999a67Sdrh #include "tcl.h" 202f999a67Sdrh #include <stdlib.h> 212f999a67Sdrh #include <string.h> 222f999a67Sdrh #include <assert.h> 232f999a67Sdrh 24*d09414cdSdanielk1977 const char *sqlite3TestErrorName(int); 25*d09414cdSdanielk1977 262f999a67Sdrh /* 272f999a67Sdrh ** Transform pointers to text and back again 282f999a67Sdrh */ 292f999a67Sdrh static void pointerToText(void *p, char *z){ 302f999a67Sdrh static const char zHex[] = "0123456789abcdef"; 312f999a67Sdrh int i, k; 324a50aac5Sdrh unsigned int u; 334a50aac5Sdrh sqlite3_uint64 n; 344a50aac5Sdrh if( sizeof(n)==sizeof(p) ){ 354a50aac5Sdrh memcpy(&n, &p, sizeof(p)); 364a50aac5Sdrh }else if( sizeof(u)==sizeof(p) ){ 374a50aac5Sdrh memcpy(&u, &p, sizeof(u)); 384a50aac5Sdrh n = u; 394a50aac5Sdrh }else{ 404a50aac5Sdrh assert( 0 ); 414a50aac5Sdrh } 422f999a67Sdrh for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 432f999a67Sdrh z[k] = zHex[n&0xf]; 442f999a67Sdrh n >>= 4; 452f999a67Sdrh } 462f999a67Sdrh z[sizeof(p)*2] = 0; 472f999a67Sdrh } 482f999a67Sdrh static int hexToInt(int h){ 492f999a67Sdrh if( h>='0' && h<='9' ){ 502f999a67Sdrh return h - '0'; 512f999a67Sdrh }else if( h>='a' && h<='f' ){ 522f999a67Sdrh return h - 'a' + 10; 532f999a67Sdrh }else{ 542f999a67Sdrh return -1; 552f999a67Sdrh } 562f999a67Sdrh } 572f999a67Sdrh static int textToPointer(const char *z, void **pp){ 582f999a67Sdrh sqlite3_uint64 n = 0; 592f999a67Sdrh int i; 604a50aac5Sdrh unsigned int u; 612f999a67Sdrh for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 622f999a67Sdrh int v; 632f999a67Sdrh v = hexToInt(*z++); 642f999a67Sdrh if( v<0 ) return TCL_ERROR; 652f999a67Sdrh n = n*16 + v; 662f999a67Sdrh } 672f999a67Sdrh if( *z!=0 ) return TCL_ERROR; 684a50aac5Sdrh if( sizeof(n)==sizeof(*pp) ){ 694a50aac5Sdrh memcpy(pp, &n, sizeof(n)); 704a50aac5Sdrh }else if( sizeof(u)==sizeof(*pp) ){ 714a50aac5Sdrh u = (unsigned int)n; 724a50aac5Sdrh memcpy(pp, &u, sizeof(u)); 734a50aac5Sdrh }else{ 744a50aac5Sdrh assert( 0 ); 754a50aac5Sdrh } 762f999a67Sdrh return TCL_OK; 772f999a67Sdrh } 782f999a67Sdrh 792f999a67Sdrh /* 802f999a67Sdrh ** Usage: sqlite3_malloc NBYTES 812f999a67Sdrh ** 822f999a67Sdrh ** Raw test interface for sqlite3_malloc(). 832f999a67Sdrh */ 842f999a67Sdrh static int test_malloc( 852f999a67Sdrh void * clientData, 862f999a67Sdrh Tcl_Interp *interp, 872f999a67Sdrh int objc, 882f999a67Sdrh Tcl_Obj *CONST objv[] 892f999a67Sdrh ){ 902f999a67Sdrh int nByte; 912f999a67Sdrh void *p; 922f999a67Sdrh char zOut[100]; 932f999a67Sdrh if( objc!=2 ){ 942f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 952f999a67Sdrh return TCL_ERROR; 962f999a67Sdrh } 972f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 982f999a67Sdrh p = sqlite3_malloc((unsigned)nByte); 992f999a67Sdrh pointerToText(p, zOut); 1002f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 1012f999a67Sdrh return TCL_OK; 1022f999a67Sdrh } 1032f999a67Sdrh 1042f999a67Sdrh /* 1052f999a67Sdrh ** Usage: sqlite3_realloc PRIOR NBYTES 1062f999a67Sdrh ** 1072f999a67Sdrh ** Raw test interface for sqlite3_realloc(). 1082f999a67Sdrh */ 1092f999a67Sdrh static int test_realloc( 1102f999a67Sdrh void * clientData, 1112f999a67Sdrh Tcl_Interp *interp, 1122f999a67Sdrh int objc, 1132f999a67Sdrh Tcl_Obj *CONST objv[] 1142f999a67Sdrh ){ 1152f999a67Sdrh int nByte; 1162f999a67Sdrh void *pPrior, *p; 1172f999a67Sdrh char zOut[100]; 1182f999a67Sdrh if( objc!=3 ){ 1192f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 1202f999a67Sdrh return TCL_ERROR; 1212f999a67Sdrh } 1222f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 1232f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 1242f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 1252f999a67Sdrh return TCL_ERROR; 1262f999a67Sdrh } 1272f999a67Sdrh p = sqlite3_realloc(pPrior, (unsigned)nByte); 1282f999a67Sdrh pointerToText(p, zOut); 1292f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 1302f999a67Sdrh return TCL_OK; 1312f999a67Sdrh } 1322f999a67Sdrh 1332f999a67Sdrh 1342f999a67Sdrh /* 1352f999a67Sdrh ** Usage: sqlite3_free PRIOR 1362f999a67Sdrh ** 1372f999a67Sdrh ** Raw test interface for sqlite3_free(). 1382f999a67Sdrh */ 1392f999a67Sdrh static int test_free( 1402f999a67Sdrh void * clientData, 1412f999a67Sdrh Tcl_Interp *interp, 1422f999a67Sdrh int objc, 1432f999a67Sdrh Tcl_Obj *CONST objv[] 1442f999a67Sdrh ){ 1452f999a67Sdrh void *pPrior; 1462f999a67Sdrh if( objc!=2 ){ 1472f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 1482f999a67Sdrh return TCL_ERROR; 1492f999a67Sdrh } 1502f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 1512f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 1522f999a67Sdrh return TCL_ERROR; 1532f999a67Sdrh } 1542f999a67Sdrh sqlite3_free(pPrior); 1552f999a67Sdrh return TCL_OK; 1562f999a67Sdrh } 1572f999a67Sdrh 1582f999a67Sdrh /* 1599c7a60dfSdrh ** These routines are in test_hexio.c 1609c7a60dfSdrh */ 1619c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *); 1629c7a60dfSdrh int sqlite3TestBinToHex(char*,int); 1639c7a60dfSdrh 1649c7a60dfSdrh /* 1659c7a60dfSdrh ** Usage: memset ADDRESS SIZE HEX 1669c7a60dfSdrh ** 1679c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a 1689c7a60dfSdrh ** specified hex pattern. 1699c7a60dfSdrh */ 1709c7a60dfSdrh static int test_memset( 1719c7a60dfSdrh void * clientData, 1729c7a60dfSdrh Tcl_Interp *interp, 1739c7a60dfSdrh int objc, 1749c7a60dfSdrh Tcl_Obj *CONST objv[] 1759c7a60dfSdrh ){ 1769c7a60dfSdrh void *p; 1779c7a60dfSdrh int size, n, i; 1789c7a60dfSdrh char *zHex; 1799c7a60dfSdrh char *zOut; 1809c7a60dfSdrh char zBin[100]; 1819c7a60dfSdrh 1829c7a60dfSdrh if( objc!=4 ){ 1839c7a60dfSdrh Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX"); 1849c7a60dfSdrh return TCL_ERROR; 1859c7a60dfSdrh } 1869c7a60dfSdrh if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 1879c7a60dfSdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 1889c7a60dfSdrh return TCL_ERROR; 1899c7a60dfSdrh } 1909c7a60dfSdrh if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 1919c7a60dfSdrh return TCL_ERROR; 1929c7a60dfSdrh } 1939c7a60dfSdrh if( size<=0 ){ 1949c7a60dfSdrh Tcl_AppendResult(interp, "size must be positive", (char*)0); 1959c7a60dfSdrh return TCL_ERROR; 1969c7a60dfSdrh } 1979c7a60dfSdrh zHex = Tcl_GetStringFromObj(objv[3], &n); 1989c7a60dfSdrh if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2; 1999c7a60dfSdrh n = sqlite3TestHexToBin(zHex, n, zBin); 2009c7a60dfSdrh if( n==0 ){ 2019c7a60dfSdrh Tcl_AppendResult(interp, "no data", (char*)0); 2029c7a60dfSdrh return TCL_ERROR; 2039c7a60dfSdrh } 2049c7a60dfSdrh zOut = p; 2059c7a60dfSdrh for(i=0; i<size; i++){ 2069c7a60dfSdrh zOut[i] = zBin[i%n]; 2079c7a60dfSdrh } 2089c7a60dfSdrh return TCL_OK; 2099c7a60dfSdrh } 2109c7a60dfSdrh 2119c7a60dfSdrh /* 2129c7a60dfSdrh ** Usage: memget ADDRESS SIZE 2139c7a60dfSdrh ** 2149c7a60dfSdrh ** Return memory as hexadecimal text. 2159c7a60dfSdrh */ 2169c7a60dfSdrh static int test_memget( 2179c7a60dfSdrh void * clientData, 2189c7a60dfSdrh Tcl_Interp *interp, 2199c7a60dfSdrh int objc, 2209c7a60dfSdrh Tcl_Obj *CONST objv[] 2219c7a60dfSdrh ){ 2229c7a60dfSdrh void *p; 2239c7a60dfSdrh int size, n; 2249c7a60dfSdrh char *zBin; 2259c7a60dfSdrh char zHex[100]; 2269c7a60dfSdrh 2279c7a60dfSdrh if( objc!=3 ){ 2289c7a60dfSdrh Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE"); 2299c7a60dfSdrh return TCL_ERROR; 2309c7a60dfSdrh } 2319c7a60dfSdrh if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 2329c7a60dfSdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 2339c7a60dfSdrh return TCL_ERROR; 2349c7a60dfSdrh } 2359c7a60dfSdrh if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 2369c7a60dfSdrh return TCL_ERROR; 2379c7a60dfSdrh } 2389c7a60dfSdrh if( size<=0 ){ 2399c7a60dfSdrh Tcl_AppendResult(interp, "size must be positive", (char*)0); 2409c7a60dfSdrh return TCL_ERROR; 2419c7a60dfSdrh } 2429c7a60dfSdrh zBin = p; 2439c7a60dfSdrh while( size>0 ){ 2449c7a60dfSdrh if( size>(sizeof(zHex)-1)/2 ){ 2459c7a60dfSdrh n = (sizeof(zHex)-1)/2; 2469c7a60dfSdrh }else{ 2479c7a60dfSdrh n = size; 2489c7a60dfSdrh } 2499c7a60dfSdrh memcpy(zHex, zBin, n); 2509c7a60dfSdrh zBin += n; 2519c7a60dfSdrh size -= n; 2529c7a60dfSdrh sqlite3TestBinToHex(zHex, n); 2539c7a60dfSdrh Tcl_AppendResult(interp, zHex, (char*)0); 2549c7a60dfSdrh } 2559c7a60dfSdrh return TCL_OK; 2569c7a60dfSdrh } 2579c7a60dfSdrh 2589c7a60dfSdrh /* 2592f999a67Sdrh ** Usage: sqlite3_memory_used 2602f999a67Sdrh ** 2612f999a67Sdrh ** Raw test interface for sqlite3_memory_used(). 2622f999a67Sdrh */ 2632f999a67Sdrh static int test_memory_used( 2642f999a67Sdrh void * clientData, 2652f999a67Sdrh Tcl_Interp *interp, 2662f999a67Sdrh int objc, 2672f999a67Sdrh Tcl_Obj *CONST objv[] 2682f999a67Sdrh ){ 2692f999a67Sdrh Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 2702f999a67Sdrh return TCL_OK; 2712f999a67Sdrh } 2722f999a67Sdrh 2732f999a67Sdrh /* 2742f999a67Sdrh ** Usage: sqlite3_memory_highwater ?RESETFLAG? 2752f999a67Sdrh ** 2762f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater(). 2772f999a67Sdrh */ 2782f999a67Sdrh static int test_memory_highwater( 2792f999a67Sdrh void * clientData, 2802f999a67Sdrh Tcl_Interp *interp, 2812f999a67Sdrh int objc, 2822f999a67Sdrh Tcl_Obj *CONST objv[] 2832f999a67Sdrh ){ 2842f999a67Sdrh int resetFlag = 0; 2852f999a67Sdrh if( objc!=1 && objc!=2 ){ 2862f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 2872f999a67Sdrh return TCL_ERROR; 2882f999a67Sdrh } 2892f999a67Sdrh if( objc==2 ){ 2902f999a67Sdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 2912f999a67Sdrh } 2922f999a67Sdrh Tcl_SetObjResult(interp, 2932f999a67Sdrh Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 2942f999a67Sdrh return TCL_OK; 2952f999a67Sdrh } 2962f999a67Sdrh 2972f999a67Sdrh /* 2982f999a67Sdrh ** Usage: sqlite3_memdebug_backtrace DEPTH 2992f999a67Sdrh ** 3002f999a67Sdrh ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 3012f999a67Sdrh ** then this routine is a no-op. 3022f999a67Sdrh */ 3032f999a67Sdrh static int test_memdebug_backtrace( 3042f999a67Sdrh void * clientData, 3052f999a67Sdrh Tcl_Interp *interp, 3062f999a67Sdrh int objc, 3072f999a67Sdrh Tcl_Obj *CONST objv[] 3082f999a67Sdrh ){ 3092f999a67Sdrh int depth; 3102f999a67Sdrh if( objc!=2 ){ 3112f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 3122f999a67Sdrh return TCL_ERROR; 3132f999a67Sdrh } 3142f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 3152f999a67Sdrh #ifdef SQLITE_MEMDEBUG 3162f999a67Sdrh { 31749e4fd71Sdrh extern void sqlite3MemdebugBacktrace(int); 31849e4fd71Sdrh sqlite3MemdebugBacktrace(depth); 3192f999a67Sdrh } 3202f999a67Sdrh #endif 3212f999a67Sdrh return TCL_OK; 3222f999a67Sdrh } 3232f999a67Sdrh 3242f999a67Sdrh /* 3252f999a67Sdrh ** Usage: sqlite3_memdebug_dump FILENAME 3262f999a67Sdrh ** 3272f999a67Sdrh ** Write a summary of unfreed memory to FILENAME. 3282f999a67Sdrh */ 3292f999a67Sdrh static int test_memdebug_dump( 3302f999a67Sdrh void * clientData, 3312f999a67Sdrh Tcl_Interp *interp, 3322f999a67Sdrh int objc, 3332f999a67Sdrh Tcl_Obj *CONST objv[] 3342f999a67Sdrh ){ 3352f999a67Sdrh if( objc!=2 ){ 3362f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 3372f999a67Sdrh return TCL_ERROR; 3382f999a67Sdrh } 3392d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ 3402d7636e2Sdrh || defined(SQLITE_POW2_MEMORY_SIZE) 3412f999a67Sdrh { 34249e4fd71Sdrh extern void sqlite3MemdebugDump(const char*); 34349e4fd71Sdrh sqlite3MemdebugDump(Tcl_GetString(objv[1])); 3442f999a67Sdrh } 3452f999a67Sdrh #endif 3462f999a67Sdrh return TCL_OK; 3472f999a67Sdrh } 3482f999a67Sdrh 349a7a8e14bSdanielk1977 /* 350a7a8e14bSdanielk1977 ** Usage: sqlite3_memdebug_malloc_count 351a7a8e14bSdanielk1977 ** 352a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called. 353a7a8e14bSdanielk1977 */ 354a7a8e14bSdanielk1977 static int test_memdebug_malloc_count( 355a7a8e14bSdanielk1977 void * clientData, 356a7a8e14bSdanielk1977 Tcl_Interp *interp, 357a7a8e14bSdanielk1977 int objc, 358a7a8e14bSdanielk1977 Tcl_Obj *CONST objv[] 359a7a8e14bSdanielk1977 ){ 360a7a8e14bSdanielk1977 int nMalloc = -1; 361a7a8e14bSdanielk1977 if( objc!=1 ){ 362a7a8e14bSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, ""); 363a7a8e14bSdanielk1977 return TCL_ERROR; 364a7a8e14bSdanielk1977 } 365a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG) 366a7a8e14bSdanielk1977 { 36749e4fd71Sdrh extern int sqlite3MemdebugMallocCount(); 36849e4fd71Sdrh nMalloc = sqlite3MemdebugMallocCount(); 369a7a8e14bSdanielk1977 } 370a7a8e14bSdanielk1977 #endif 371a7a8e14bSdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); 372a7a8e14bSdanielk1977 return TCL_OK; 373a7a8e14bSdanielk1977 } 374a7a8e14bSdanielk1977 3752f999a67Sdrh 3762f999a67Sdrh /* 377a1644fd8Sdanielk1977 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? 378a1644fd8Sdanielk1977 ** 379a1644fd8Sdanielk1977 ** where options are: 380a1644fd8Sdanielk1977 ** 381643167ffSdrh ** -repeat <count> 382a1644fd8Sdanielk1977 ** -benigncnt <varname> 3830e6f1546Sdrh ** 3840e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes. 385643167ffSdrh ** If a repeat count is specified, the fault is repeated that many 386643167ffSdrh ** times. 3870e6f1546Sdrh ** 3880e6f1546Sdrh ** Each call to this routine overrides the prior counter value. 3890e6f1546Sdrh ** This routine returns the number of simulated failures that have 3900e6f1546Sdrh ** happened since the previous call to this routine. 3910e6f1546Sdrh ** 3920e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1. 3930e6f1546Sdrh */ 3940e6f1546Sdrh static int test_memdebug_fail( 3950e6f1546Sdrh void * clientData, 3960e6f1546Sdrh Tcl_Interp *interp, 3970e6f1546Sdrh int objc, 3980e6f1546Sdrh Tcl_Obj *CONST objv[] 3990e6f1546Sdrh ){ 400a1644fd8Sdanielk1977 int ii; 4010e6f1546Sdrh int iFail; 402643167ffSdrh int nRepeat = 1; 403a1644fd8Sdanielk1977 Tcl_Obj *pBenignCnt = 0; 404643167ffSdrh int nBenign; 4050e6f1546Sdrh int nFail = 0; 406a1644fd8Sdanielk1977 407a1644fd8Sdanielk1977 if( objc<2 ){ 408a1644fd8Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); 4090e6f1546Sdrh return TCL_ERROR; 4100e6f1546Sdrh } 4110e6f1546Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 412a1644fd8Sdanielk1977 413a1644fd8Sdanielk1977 for(ii=2; ii<objc; ii+=2){ 414a1644fd8Sdanielk1977 int nOption; 415a1644fd8Sdanielk1977 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); 416a1644fd8Sdanielk1977 char *zErr = 0; 417a1644fd8Sdanielk1977 418a1644fd8Sdanielk1977 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ 419a1644fd8Sdanielk1977 if( ii==(objc-1) ){ 420a1644fd8Sdanielk1977 zErr = "option requires an argument: "; 421ed138fb3Sdrh }else{ 422643167ffSdrh if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ 423a1644fd8Sdanielk1977 return TCL_ERROR; 424ed138fb3Sdrh } 425a1644fd8Sdanielk1977 } 426a1644fd8Sdanielk1977 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ 427a1644fd8Sdanielk1977 if( ii==(objc-1) ){ 428a1644fd8Sdanielk1977 zErr = "option requires an argument: "; 429a1644fd8Sdanielk1977 }else{ 430a1644fd8Sdanielk1977 pBenignCnt = objv[ii+1]; 431a1644fd8Sdanielk1977 } 432a1644fd8Sdanielk1977 }else{ 433a1644fd8Sdanielk1977 zErr = "unknown option: "; 434a1644fd8Sdanielk1977 } 435a1644fd8Sdanielk1977 436a1644fd8Sdanielk1977 if( zErr ){ 437a1644fd8Sdanielk1977 Tcl_AppendResult(interp, zErr, zOption, 0); 438a1644fd8Sdanielk1977 return TCL_ERROR; 439a1644fd8Sdanielk1977 } 440a1644fd8Sdanielk1977 } 441a1644fd8Sdanielk1977 44277db4c05Sdrh sqlite3_test_control(-12345); /* Just to stress the test_control interface */ 443ed13d98cSdrh nBenign = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES, 444ed13d98cSdrh SQLITE_FAULTINJECTOR_MALLOC); 445ed13d98cSdrh nFail = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_FAILURES, 446ed13d98cSdrh SQLITE_FAULTINJECTOR_MALLOC); 447ed13d98cSdrh sqlite3_test_control(SQLITE_TESTCTRL_FAULT_CONFIG, 448ed13d98cSdrh SQLITE_FAULTINJECTOR_MALLOC, iFail, nRepeat); 449a1644fd8Sdanielk1977 if( pBenignCnt ){ 450643167ffSdrh Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); 451a1644fd8Sdanielk1977 } 4520e6f1546Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 4530e6f1546Sdrh return TCL_OK; 4540e6f1546Sdrh } 4550e6f1546Sdrh 456cd03724cSdanielk1977 /* 457cd03724cSdanielk1977 ** Usage: sqlite3_memdebug_pending 458cd03724cSdanielk1977 ** 459cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a 460cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that 461cd03724cSdanielk1977 ** no malloc() failure is scheduled. 462cd03724cSdanielk1977 */ 463cd03724cSdanielk1977 static int test_memdebug_pending( 464cd03724cSdanielk1977 void * clientData, 465cd03724cSdanielk1977 Tcl_Interp *interp, 466cd03724cSdanielk1977 int objc, 467cd03724cSdanielk1977 Tcl_Obj *CONST objv[] 468cd03724cSdanielk1977 ){ 4695efaf070Sdrh int nPending; 470cd03724cSdanielk1977 if( objc!=1 ){ 471cd03724cSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, ""); 472cd03724cSdanielk1977 return TCL_ERROR; 473cd03724cSdanielk1977 } 4745efaf070Sdrh nPending = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_PENDING, 475ed13d98cSdrh SQLITE_FAULTINJECTOR_MALLOC); 476ed13d98cSdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending)); 477cd03724cSdanielk1977 return TCL_OK; 478cd03724cSdanielk1977 } 479cd03724cSdanielk1977 4800e6f1546Sdrh 4810e6f1546Sdrh /* 4824a50aac5Sdrh ** Usage: sqlite3_memdebug_settitle TITLE 4834a50aac5Sdrh ** 4844a50aac5Sdrh ** Set a title string stored with each allocation. The TITLE is 4854a50aac5Sdrh ** typically the name of the test that was running when the 4864a50aac5Sdrh ** allocation occurred. The TITLE is stored with the allocation 4874a50aac5Sdrh ** and can be used to figure out which tests are leaking memory. 4884a50aac5Sdrh ** 4894a50aac5Sdrh ** Each title overwrite the previous. 4904a50aac5Sdrh */ 4914a50aac5Sdrh static int test_memdebug_settitle( 4924a50aac5Sdrh void * clientData, 4934a50aac5Sdrh Tcl_Interp *interp, 4944a50aac5Sdrh int objc, 4954a50aac5Sdrh Tcl_Obj *CONST objv[] 4964a50aac5Sdrh ){ 4974a50aac5Sdrh const char *zTitle; 4984a50aac5Sdrh if( objc!=2 ){ 4994a50aac5Sdrh Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); 5004a50aac5Sdrh return TCL_ERROR; 5014a50aac5Sdrh } 5024a50aac5Sdrh zTitle = Tcl_GetString(objv[1]); 5034a50aac5Sdrh #ifdef SQLITE_MEMDEBUG 5044a50aac5Sdrh { 50549e4fd71Sdrh extern int sqlite3MemdebugSettitle(const char*); 50649e4fd71Sdrh sqlite3MemdebugSettitle(zTitle); 5074a50aac5Sdrh } 5084a50aac5Sdrh #endif 5094a50aac5Sdrh return TCL_OK; 5104a50aac5Sdrh } 5114a50aac5Sdrh 512cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES 10 5136f332c18Sdanielk1977 static Tcl_HashTable aMallocLog; 5146f332c18Sdanielk1977 static int mallocLogEnabled = 0; 5156f332c18Sdanielk1977 5166f332c18Sdanielk1977 typedef struct MallocLog MallocLog; 5176f332c18Sdanielk1977 struct MallocLog { 5186f332c18Sdanielk1977 int nCall; 5196f332c18Sdanielk1977 int nByte; 5206f332c18Sdanielk1977 }; 5216f332c18Sdanielk1977 522afdd23a4Sshane #ifdef SQLITE_MEMDEBUG 5236f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ 5246f332c18Sdanielk1977 if( mallocLogEnabled ){ 5256f332c18Sdanielk1977 MallocLog *pLog; 5266f332c18Sdanielk1977 Tcl_HashEntry *pEntry; 5276f332c18Sdanielk1977 int isNew; 5286f332c18Sdanielk1977 5296f332c18Sdanielk1977 int aKey[MALLOC_LOG_FRAMES]; 5306f332c18Sdanielk1977 int nKey = sizeof(int)*MALLOC_LOG_FRAMES; 5316f332c18Sdanielk1977 5326f332c18Sdanielk1977 memset(aKey, 0, nKey); 5336f332c18Sdanielk1977 if( (sizeof(void*)*nFrame)<nKey ){ 5346f332c18Sdanielk1977 nKey = nFrame*sizeof(void*); 5356f332c18Sdanielk1977 } 5366f332c18Sdanielk1977 memcpy(aKey, aFrame, nKey); 5376f332c18Sdanielk1977 5386f332c18Sdanielk1977 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); 5396f332c18Sdanielk1977 if( isNew ){ 5406f332c18Sdanielk1977 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); 5416f332c18Sdanielk1977 memset(pLog, 0, sizeof(MallocLog)); 5426f332c18Sdanielk1977 Tcl_SetHashValue(pEntry, (ClientData)pLog); 5436f332c18Sdanielk1977 }else{ 5446f332c18Sdanielk1977 pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 5456f332c18Sdanielk1977 } 5466f332c18Sdanielk1977 5476f332c18Sdanielk1977 pLog->nCall++; 5486f332c18Sdanielk1977 pLog->nByte += nByte; 5496f332c18Sdanielk1977 } 5506f332c18Sdanielk1977 } 551afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */ 5526f332c18Sdanielk1977 5535f096135Sdanielk1977 static void test_memdebug_log_clear(){ 554dbdc4d49Sdanielk1977 Tcl_HashSearch search; 555dbdc4d49Sdanielk1977 Tcl_HashEntry *pEntry; 556dbdc4d49Sdanielk1977 for( 557dbdc4d49Sdanielk1977 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 558dbdc4d49Sdanielk1977 pEntry; 559dbdc4d49Sdanielk1977 pEntry=Tcl_NextHashEntry(&search) 560dbdc4d49Sdanielk1977 ){ 561dbdc4d49Sdanielk1977 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 562dbdc4d49Sdanielk1977 Tcl_Free((char *)pLog); 563dbdc4d49Sdanielk1977 } 564dbdc4d49Sdanielk1977 Tcl_DeleteHashTable(&aMallocLog); 565dbdc4d49Sdanielk1977 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 566dbdc4d49Sdanielk1977 } 567dbdc4d49Sdanielk1977 5686f332c18Sdanielk1977 static int test_memdebug_log( 5696f332c18Sdanielk1977 void * clientData, 5706f332c18Sdanielk1977 Tcl_Interp *interp, 5716f332c18Sdanielk1977 int objc, 5726f332c18Sdanielk1977 Tcl_Obj *CONST objv[] 5736f332c18Sdanielk1977 ){ 5746f332c18Sdanielk1977 static int isInit = 0; 5756f332c18Sdanielk1977 int iSub; 5766f332c18Sdanielk1977 577dbdc4d49Sdanielk1977 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" }; 578dbdc4d49Sdanielk1977 enum MB_enum { 579dbdc4d49Sdanielk1977 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC 580dbdc4d49Sdanielk1977 }; 5816f332c18Sdanielk1977 5826f332c18Sdanielk1977 if( !isInit ){ 5836f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG 5846f332c18Sdanielk1977 extern void sqlite3MemdebugBacktraceCallback( 5856f332c18Sdanielk1977 void (*xBacktrace)(int, int, void **)); 5866f332c18Sdanielk1977 sqlite3MemdebugBacktraceCallback(test_memdebug_callback); 5876f332c18Sdanielk1977 #endif 5886f332c18Sdanielk1977 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 5896f332c18Sdanielk1977 isInit = 1; 5906f332c18Sdanielk1977 } 5916f332c18Sdanielk1977 5926f332c18Sdanielk1977 if( objc<2 ){ 5936f332c18Sdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 5946f332c18Sdanielk1977 } 5956f332c18Sdanielk1977 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ 5966f332c18Sdanielk1977 return TCL_ERROR; 5976f332c18Sdanielk1977 } 5986f332c18Sdanielk1977 5996f332c18Sdanielk1977 switch( (enum MB_enum)iSub ){ 6006f332c18Sdanielk1977 case MB_LOG_START: 6016f332c18Sdanielk1977 mallocLogEnabled = 1; 6026f332c18Sdanielk1977 break; 6036f332c18Sdanielk1977 case MB_LOG_STOP: 6046f332c18Sdanielk1977 mallocLogEnabled = 0; 6056f332c18Sdanielk1977 break; 6066f332c18Sdanielk1977 case MB_LOG_DUMP: { 6076f332c18Sdanielk1977 Tcl_HashSearch search; 6086f332c18Sdanielk1977 Tcl_HashEntry *pEntry; 6096f332c18Sdanielk1977 Tcl_Obj *pRet = Tcl_NewObj(); 6106f332c18Sdanielk1977 6116f332c18Sdanielk1977 assert(sizeof(int)==sizeof(void*)); 6126f332c18Sdanielk1977 6136f332c18Sdanielk1977 for( 6146f332c18Sdanielk1977 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 6156f332c18Sdanielk1977 pEntry; 6166f332c18Sdanielk1977 pEntry=Tcl_NextHashEntry(&search) 6176f332c18Sdanielk1977 ){ 6186f332c18Sdanielk1977 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; 6196f332c18Sdanielk1977 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 6206f332c18Sdanielk1977 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry); 6216f332c18Sdanielk1977 int ii; 6226f332c18Sdanielk1977 6236f332c18Sdanielk1977 apElem[0] = Tcl_NewIntObj(pLog->nCall); 6246f332c18Sdanielk1977 apElem[1] = Tcl_NewIntObj(pLog->nByte); 6256f332c18Sdanielk1977 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ 6266f332c18Sdanielk1977 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]); 6276f332c18Sdanielk1977 } 6286f332c18Sdanielk1977 6296f332c18Sdanielk1977 Tcl_ListObjAppendElement(interp, pRet, 6306f332c18Sdanielk1977 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) 6316f332c18Sdanielk1977 ); 6326f332c18Sdanielk1977 } 6336f332c18Sdanielk1977 6346f332c18Sdanielk1977 Tcl_SetObjResult(interp, pRet); 6356f332c18Sdanielk1977 break; 6366f332c18Sdanielk1977 } 6376f332c18Sdanielk1977 case MB_LOG_CLEAR: { 638dbdc4d49Sdanielk1977 test_memdebug_log_clear(); 639dbdc4d49Sdanielk1977 break; 6406f332c18Sdanielk1977 } 641dbdc4d49Sdanielk1977 642dbdc4d49Sdanielk1977 case MB_LOG_SYNC: { 643b940492eSdrh #ifdef SQLITE_MEMDEBUG 644dbdc4d49Sdanielk1977 extern void sqlite3MemdebugSync(); 645dbdc4d49Sdanielk1977 test_memdebug_log_clear(); 646dbdc4d49Sdanielk1977 mallocLogEnabled = 1; 647dbdc4d49Sdanielk1977 sqlite3MemdebugSync(); 648b940492eSdrh #endif 649dbdc4d49Sdanielk1977 break; 6506f332c18Sdanielk1977 } 6516f332c18Sdanielk1977 } 6526f332c18Sdanielk1977 6536f332c18Sdanielk1977 return TCL_OK; 6546f332c18Sdanielk1977 } 6554a50aac5Sdrh 6564a50aac5Sdrh /* 6579ac3fe97Sdrh ** Usage: sqlite3_config_scratch SIZE N 6589ac3fe97Sdrh ** 6599ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. 6609ac3fe97Sdrh ** The buffer is static and is of limited size. N might be 6619ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size. 6629ac3fe97Sdrh ** The revised value of N is returned. 6639ac3fe97Sdrh ** 6649ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL. 6659ac3fe97Sdrh */ 6669ac3fe97Sdrh static int test_config_scratch( 6679ac3fe97Sdrh void * clientData, 6689ac3fe97Sdrh Tcl_Interp *interp, 6699ac3fe97Sdrh int objc, 6709ac3fe97Sdrh Tcl_Obj *CONST objv[] 6719ac3fe97Sdrh ){ 6729ac3fe97Sdrh int sz, N, rc; 6739ac3fe97Sdrh Tcl_Obj *pResult; 674f7141990Sdrh static char buf[30000]; 6759ac3fe97Sdrh if( objc!=3 ){ 6769ac3fe97Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 6779ac3fe97Sdrh return TCL_ERROR; 6789ac3fe97Sdrh } 679f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 680f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 6819ac3fe97Sdrh if( sz<0 ){ 6829ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); 683f7141990Sdrh }else{ 6849ac3fe97Sdrh int mx = sizeof(buf)/(sz+4); 6859ac3fe97Sdrh if( N>mx ) N = mx; 6869ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); 6879ac3fe97Sdrh } 6889ac3fe97Sdrh pResult = Tcl_NewObj(); 6899ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 6909ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 6919ac3fe97Sdrh Tcl_SetObjResult(interp, pResult); 6929ac3fe97Sdrh return TCL_OK; 6939ac3fe97Sdrh } 6949ac3fe97Sdrh 6959ac3fe97Sdrh /* 6969ac3fe97Sdrh ** Usage: sqlite3_config_pagecache SIZE N 6979ac3fe97Sdrh ** 6989ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. 6999ac3fe97Sdrh ** The buffer is static and is of limited size. N might be 7009ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size. 7019ac3fe97Sdrh ** The revised value of N is returned. 7029ac3fe97Sdrh ** 7039ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL. 7049ac3fe97Sdrh */ 7059ac3fe97Sdrh static int test_config_pagecache( 7069ac3fe97Sdrh void * clientData, 7079ac3fe97Sdrh Tcl_Interp *interp, 7089ac3fe97Sdrh int objc, 7099ac3fe97Sdrh Tcl_Obj *CONST objv[] 7109ac3fe97Sdrh ){ 7119ac3fe97Sdrh int sz, N, rc; 7129ac3fe97Sdrh Tcl_Obj *pResult; 7139ac3fe97Sdrh static char buf[100000]; 7149ac3fe97Sdrh if( objc!=3 ){ 7159ac3fe97Sdrh Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 7169ac3fe97Sdrh return TCL_ERROR; 7179ac3fe97Sdrh } 718f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 719f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 7209ac3fe97Sdrh if( sz<0 ){ 721f7141990Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); 722f7141990Sdrh }else{ 7239ac3fe97Sdrh int mx = sizeof(buf)/(sz+4); 7249ac3fe97Sdrh if( N>mx ) N = mx; 7259ac3fe97Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); 7269ac3fe97Sdrh } 7279ac3fe97Sdrh pResult = Tcl_NewObj(); 7289ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 7299ac3fe97Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 7309ac3fe97Sdrh Tcl_SetObjResult(interp, pResult); 7319ac3fe97Sdrh return TCL_OK; 7329ac3fe97Sdrh } 7339ac3fe97Sdrh 734f7141990Sdrh /* 735f7141990Sdrh ** Usage: sqlite3_status OPCODE RESETFLAG 736f7141990Sdrh ** 737f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return 738f7141990Sdrh ** code, the current value, and the high-water mark value. 739f7141990Sdrh */ 740f7141990Sdrh static int test_status( 741f7141990Sdrh void * clientData, 742f7141990Sdrh Tcl_Interp *interp, 743f7141990Sdrh int objc, 744f7141990Sdrh Tcl_Obj *CONST objv[] 745f7141990Sdrh ){ 746f7141990Sdrh int rc, iValue, mxValue; 747f7141990Sdrh int i, op, resetFlag; 748f7141990Sdrh const char *zOpName; 749f7141990Sdrh static const struct { 750f7141990Sdrh const char *zName; 751f7141990Sdrh int op; 752f7141990Sdrh } aOp[] = { 753f7141990Sdrh { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, 754f7141990Sdrh { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, 755f7141990Sdrh { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, 756f7141990Sdrh { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, 757f7141990Sdrh { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, 758f7141990Sdrh { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, 759f7141990Sdrh }; 760f7141990Sdrh Tcl_Obj *pResult; 761f7141990Sdrh if( objc!=3 ){ 762f7141990Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 763f7141990Sdrh return TCL_ERROR; 764f7141990Sdrh } 765f7141990Sdrh zOpName = Tcl_GetString(objv[1]); 766f7141990Sdrh for(i=0; i<ArraySize(aOp); i++){ 767f7141990Sdrh if( strcmp(aOp[i].zName, zOpName)==0 ){ 768f7141990Sdrh op = aOp[i].op; 769f7141990Sdrh break; 770f7141990Sdrh } 771f7141990Sdrh } 772f7141990Sdrh if( i>=ArraySize(aOp) ){ 773f7141990Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; 774f7141990Sdrh } 775f7141990Sdrh if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; 776f7141990Sdrh rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); 777f7141990Sdrh pResult = Tcl_NewObj(); 778f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 779f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 780f7141990Sdrh Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 781f7141990Sdrh Tcl_SetObjResult(interp, pResult); 782f7141990Sdrh return TCL_OK; 783f7141990Sdrh } 7849ac3fe97Sdrh 7859ac3fe97Sdrh /* 786*d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN 787*d09414cdSdanielk1977 */ 788*d09414cdSdanielk1977 static int test_install_malloc_faultsim( 789*d09414cdSdanielk1977 void * clientData, 790*d09414cdSdanielk1977 Tcl_Interp *interp, 791*d09414cdSdanielk1977 int objc, 792*d09414cdSdanielk1977 Tcl_Obj *CONST objv[] 793*d09414cdSdanielk1977 ){ 794*d09414cdSdanielk1977 int rc; 795*d09414cdSdanielk1977 int isInstall; 796*d09414cdSdanielk1977 797*d09414cdSdanielk1977 if( objc!=2 ){ 798*d09414cdSdanielk1977 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 799*d09414cdSdanielk1977 return TCL_ERROR; 800*d09414cdSdanielk1977 } 801*d09414cdSdanielk1977 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 802*d09414cdSdanielk1977 return TCL_ERROR; 803*d09414cdSdanielk1977 } 804*d09414cdSdanielk1977 rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, isInstall); 805*d09414cdSdanielk1977 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 806*d09414cdSdanielk1977 return TCL_OK; 807*d09414cdSdanielk1977 } 808*d09414cdSdanielk1977 809*d09414cdSdanielk1977 /* 8102f999a67Sdrh ** Register commands with the TCL interpreter. 8112f999a67Sdrh */ 8122f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 8132f999a67Sdrh static struct { 8142f999a67Sdrh char *zName; 8152f999a67Sdrh Tcl_ObjCmdProc *xProc; 8162f999a67Sdrh } aObjCmd[] = { 8172f999a67Sdrh { "sqlite3_malloc", test_malloc }, 8182f999a67Sdrh { "sqlite3_realloc", test_realloc }, 8192f999a67Sdrh { "sqlite3_free", test_free }, 8209c7a60dfSdrh { "memset", test_memset }, 8219c7a60dfSdrh { "memget", test_memget }, 8222f999a67Sdrh { "sqlite3_memory_used", test_memory_used }, 8232f999a67Sdrh { "sqlite3_memory_highwater", test_memory_highwater }, 8242f999a67Sdrh { "sqlite3_memdebug_backtrace", test_memdebug_backtrace }, 8252f999a67Sdrh { "sqlite3_memdebug_dump", test_memdebug_dump }, 8260e6f1546Sdrh { "sqlite3_memdebug_fail", test_memdebug_fail }, 827cd03724cSdanielk1977 { "sqlite3_memdebug_pending", test_memdebug_pending }, 8284a50aac5Sdrh { "sqlite3_memdebug_settitle", test_memdebug_settitle }, 829a7a8e14bSdanielk1977 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count }, 8306f332c18Sdanielk1977 { "sqlite3_memdebug_log", test_memdebug_log }, 8319ac3fe97Sdrh { "sqlite3_config_scratch", test_config_scratch }, 8329ac3fe97Sdrh { "sqlite3_config_pagecache", test_config_pagecache }, 833f7141990Sdrh { "sqlite3_status", test_status }, 834*d09414cdSdanielk1977 835*d09414cdSdanielk1977 { "install_malloc_faultsim", test_install_malloc_faultsim }, 8362f999a67Sdrh }; 8372f999a67Sdrh int i; 8382f999a67Sdrh for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 8392f999a67Sdrh Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 8402f999a67Sdrh } 8412f999a67Sdrh return TCL_OK; 8422f999a67Sdrh } 843