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*ed138fb3Sdrh ** $Id: test_malloc.c,v 1.3 2007/08/22 22:04:37 drh Exp $ 172f999a67Sdrh */ 182f999a67Sdrh #include "sqliteInt.h" 192f999a67Sdrh #include "tcl.h" 202f999a67Sdrh #include <stdlib.h> 212f999a67Sdrh #include <string.h> 222f999a67Sdrh #include <assert.h> 232f999a67Sdrh 242f999a67Sdrh /* 252f999a67Sdrh ** Transform pointers to text and back again 262f999a67Sdrh */ 272f999a67Sdrh static void pointerToText(void *p, char *z){ 282f999a67Sdrh static const char zHex[] = "0123456789abcdef"; 292f999a67Sdrh int i, k; 302f999a67Sdrh sqlite3_uint64 n = (sqlite3_uint64)p; 312f999a67Sdrh for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 322f999a67Sdrh z[k] = zHex[n&0xf]; 332f999a67Sdrh n >>= 4; 342f999a67Sdrh } 352f999a67Sdrh z[sizeof(p)*2] = 0; 362f999a67Sdrh } 372f999a67Sdrh static int hexToInt(int h){ 382f999a67Sdrh if( h>='0' && h<='9' ){ 392f999a67Sdrh return h - '0'; 402f999a67Sdrh }else if( h>='a' && h<='f' ){ 412f999a67Sdrh return h - 'a' + 10; 422f999a67Sdrh }else{ 432f999a67Sdrh return -1; 442f999a67Sdrh } 452f999a67Sdrh } 462f999a67Sdrh static int textToPointer(const char *z, void **pp){ 472f999a67Sdrh sqlite3_uint64 n = 0; 482f999a67Sdrh int i; 492f999a67Sdrh for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 502f999a67Sdrh int v; 512f999a67Sdrh v = hexToInt(*z++); 522f999a67Sdrh if( v<0 ) return TCL_ERROR; 532f999a67Sdrh n = n*16 + v; 542f999a67Sdrh } 552f999a67Sdrh if( *z!=0 ) return TCL_ERROR; 562f999a67Sdrh *pp = (void*)n; 572f999a67Sdrh return TCL_OK; 582f999a67Sdrh } 592f999a67Sdrh 602f999a67Sdrh /* 612f999a67Sdrh ** Usage: sqlite3_malloc NBYTES 622f999a67Sdrh ** 632f999a67Sdrh ** Raw test interface for sqlite3_malloc(). 642f999a67Sdrh */ 652f999a67Sdrh static int test_malloc( 662f999a67Sdrh void * clientData, 672f999a67Sdrh Tcl_Interp *interp, 682f999a67Sdrh int objc, 692f999a67Sdrh Tcl_Obj *CONST objv[] 702f999a67Sdrh ){ 712f999a67Sdrh int nByte; 722f999a67Sdrh void *p; 732f999a67Sdrh char zOut[100]; 742f999a67Sdrh if( objc!=2 ){ 752f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 762f999a67Sdrh return TCL_ERROR; 772f999a67Sdrh } 782f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 792f999a67Sdrh p = sqlite3_malloc((unsigned)nByte); 802f999a67Sdrh pointerToText(p, zOut); 812f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 822f999a67Sdrh return TCL_OK; 832f999a67Sdrh } 842f999a67Sdrh 852f999a67Sdrh /* 862f999a67Sdrh ** Usage: sqlite3_realloc PRIOR NBYTES 872f999a67Sdrh ** 882f999a67Sdrh ** Raw test interface for sqlite3_realloc(). 892f999a67Sdrh */ 902f999a67Sdrh static int test_realloc( 912f999a67Sdrh void * clientData, 922f999a67Sdrh Tcl_Interp *interp, 932f999a67Sdrh int objc, 942f999a67Sdrh Tcl_Obj *CONST objv[] 952f999a67Sdrh ){ 962f999a67Sdrh int nByte; 972f999a67Sdrh void *pPrior, *p; 982f999a67Sdrh char zOut[100]; 992f999a67Sdrh if( objc!=3 ){ 1002f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 1012f999a67Sdrh return TCL_ERROR; 1022f999a67Sdrh } 1032f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 1042f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 1052f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 1062f999a67Sdrh return TCL_ERROR; 1072f999a67Sdrh } 1082f999a67Sdrh p = sqlite3_realloc(pPrior, (unsigned)nByte); 1092f999a67Sdrh pointerToText(p, zOut); 1102f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 1112f999a67Sdrh return TCL_OK; 1122f999a67Sdrh } 1132f999a67Sdrh 1142f999a67Sdrh 1152f999a67Sdrh /* 1162f999a67Sdrh ** Usage: sqlite3_free PRIOR 1172f999a67Sdrh ** 1182f999a67Sdrh ** Raw test interface for sqlite3_free(). 1192f999a67Sdrh */ 1202f999a67Sdrh static int test_free( 1212f999a67Sdrh void * clientData, 1222f999a67Sdrh Tcl_Interp *interp, 1232f999a67Sdrh int objc, 1242f999a67Sdrh Tcl_Obj *CONST objv[] 1252f999a67Sdrh ){ 1262f999a67Sdrh void *pPrior; 1272f999a67Sdrh if( objc!=2 ){ 1282f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 1292f999a67Sdrh return TCL_ERROR; 1302f999a67Sdrh } 1312f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 1322f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 1332f999a67Sdrh return TCL_ERROR; 1342f999a67Sdrh } 1352f999a67Sdrh sqlite3_free(pPrior); 1362f999a67Sdrh return TCL_OK; 1372f999a67Sdrh } 1382f999a67Sdrh 1392f999a67Sdrh /* 1402f999a67Sdrh ** Usage: sqlite3_memory_used 1412f999a67Sdrh ** 1422f999a67Sdrh ** Raw test interface for sqlite3_memory_used(). 1432f999a67Sdrh */ 1442f999a67Sdrh static int test_memory_used( 1452f999a67Sdrh void * clientData, 1462f999a67Sdrh Tcl_Interp *interp, 1472f999a67Sdrh int objc, 1482f999a67Sdrh Tcl_Obj *CONST objv[] 1492f999a67Sdrh ){ 1502f999a67Sdrh Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 1512f999a67Sdrh return TCL_OK; 1522f999a67Sdrh } 1532f999a67Sdrh 1542f999a67Sdrh /* 1552f999a67Sdrh ** Usage: sqlite3_memory_highwater ?RESETFLAG? 1562f999a67Sdrh ** 1572f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater(). 1582f999a67Sdrh */ 1592f999a67Sdrh static int test_memory_highwater( 1602f999a67Sdrh void * clientData, 1612f999a67Sdrh Tcl_Interp *interp, 1622f999a67Sdrh int objc, 1632f999a67Sdrh Tcl_Obj *CONST objv[] 1642f999a67Sdrh ){ 1652f999a67Sdrh int resetFlag = 0; 1662f999a67Sdrh if( objc!=1 && objc!=2 ){ 1672f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 1682f999a67Sdrh return TCL_ERROR; 1692f999a67Sdrh } 1702f999a67Sdrh if( objc==2 ){ 1712f999a67Sdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 1722f999a67Sdrh } 1732f999a67Sdrh Tcl_SetObjResult(interp, 1742f999a67Sdrh Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 1752f999a67Sdrh return TCL_OK; 1762f999a67Sdrh } 1772f999a67Sdrh 1782f999a67Sdrh /* 1792f999a67Sdrh ** Usage: sqlite3_memdebug_backtrace DEPTH 1802f999a67Sdrh ** 1812f999a67Sdrh ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 1822f999a67Sdrh ** then this routine is a no-op. 1832f999a67Sdrh */ 1842f999a67Sdrh static int test_memdebug_backtrace( 1852f999a67Sdrh void * clientData, 1862f999a67Sdrh Tcl_Interp *interp, 1872f999a67Sdrh int objc, 1882f999a67Sdrh Tcl_Obj *CONST objv[] 1892f999a67Sdrh ){ 1902f999a67Sdrh int depth; 1912f999a67Sdrh if( objc!=2 ){ 1922f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 1932f999a67Sdrh return TCL_ERROR; 1942f999a67Sdrh } 1952f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 1962f999a67Sdrh #ifdef SQLITE_MEMDEBUG 1972f999a67Sdrh { 1982f999a67Sdrh extern void sqlite3_memdebug_backtrace(int); 1992f999a67Sdrh sqlite3_memdebug_backtrace(depth); 2002f999a67Sdrh } 2012f999a67Sdrh #endif 2022f999a67Sdrh return TCL_OK; 2032f999a67Sdrh } 2042f999a67Sdrh 2052f999a67Sdrh /* 2062f999a67Sdrh ** Usage: sqlite3_memdebug_dump FILENAME 2072f999a67Sdrh ** 2082f999a67Sdrh ** Write a summary of unfreed memory to FILENAME. 2092f999a67Sdrh */ 2102f999a67Sdrh static int test_memdebug_dump( 2112f999a67Sdrh void * clientData, 2122f999a67Sdrh Tcl_Interp *interp, 2132f999a67Sdrh int objc, 2142f999a67Sdrh Tcl_Obj *CONST objv[] 2152f999a67Sdrh ){ 2162f999a67Sdrh if( objc!=2 ){ 2172f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 2182f999a67Sdrh return TCL_ERROR; 2192f999a67Sdrh } 2202f999a67Sdrh #ifdef SQLITE_MEMDEBUG 2212f999a67Sdrh { 2222f999a67Sdrh extern void sqlite3_memdebug_dump(const char*); 2232f999a67Sdrh sqlite3_memdebug_dump(Tcl_GetString(objv[1])); 2242f999a67Sdrh } 2252f999a67Sdrh #endif 2262f999a67Sdrh return TCL_OK; 2272f999a67Sdrh } 2282f999a67Sdrh 2292f999a67Sdrh 2302f999a67Sdrh /* 231*ed138fb3Sdrh ** Usage: sqlite3_memdebug_fail COUNTER ?REPEAT? 2320e6f1546Sdrh ** 2330e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes. 2340e6f1546Sdrh ** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is 2350e6f1546Sdrh ** 0 then only a single failure occurs. 2360e6f1546Sdrh ** 2370e6f1546Sdrh ** Each call to this routine overrides the prior counter value. 2380e6f1546Sdrh ** This routine returns the number of simulated failures that have 2390e6f1546Sdrh ** happened since the previous call to this routine. 2400e6f1546Sdrh ** 2410e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1. 2420e6f1546Sdrh */ 2430e6f1546Sdrh static int test_memdebug_fail( 2440e6f1546Sdrh void * clientData, 2450e6f1546Sdrh Tcl_Interp *interp, 2460e6f1546Sdrh int objc, 2470e6f1546Sdrh Tcl_Obj *CONST objv[] 2480e6f1546Sdrh ){ 2490e6f1546Sdrh int iFail; 2500e6f1546Sdrh int iRepeat; 2510e6f1546Sdrh int nFail = 0; 252*ed138fb3Sdrh if( objc!=3 && objc!=2 ){ 253*ed138fb3Sdrh Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?REPEAT?"); 2540e6f1546Sdrh return TCL_ERROR; 2550e6f1546Sdrh } 2560e6f1546Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 257*ed138fb3Sdrh if( objc==3 ){ 2580e6f1546Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR; 259*ed138fb3Sdrh }else{ 260*ed138fb3Sdrh iRepeat = -1; 261*ed138fb3Sdrh } 2620e6f1546Sdrh #ifdef SQLITE_MEMDEBUG 2630e6f1546Sdrh { 2640e6f1546Sdrh extern int sqlite3_memdebug_fail(int,int); 2650e6f1546Sdrh nFail = sqlite3_memdebug_fail(iFail, iRepeat); 2660e6f1546Sdrh } 2670e6f1546Sdrh #endif 2680e6f1546Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 2690e6f1546Sdrh return TCL_OK; 2700e6f1546Sdrh } 2710e6f1546Sdrh 2720e6f1546Sdrh 2730e6f1546Sdrh /* 274*ed138fb3Sdrh ** Usage: sqlite3_memdebug_pending 275*ed138fb3Sdrh ** 276*ed138fb3Sdrh ** Return the number of successful mallocs remaining before the 277*ed138fb3Sdrh ** next simulated failure. Return -1 if no simulated failure is 278*ed138fb3Sdrh ** currently scheduled. 279*ed138fb3Sdrh */ 280*ed138fb3Sdrh static int test_memdebug_pending( 281*ed138fb3Sdrh void * clientData, 282*ed138fb3Sdrh Tcl_Interp *interp, 283*ed138fb3Sdrh int objc, 284*ed138fb3Sdrh Tcl_Obj *CONST objv[] 285*ed138fb3Sdrh ){ 286*ed138fb3Sdrh extern int sqlite3_memdebug_pending(void); 287*ed138fb3Sdrh Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_pending())); 288*ed138fb3Sdrh return TCL_OK; 289*ed138fb3Sdrh } 290*ed138fb3Sdrh 291*ed138fb3Sdrh 292*ed138fb3Sdrh /* 2932f999a67Sdrh ** Register commands with the TCL interpreter. 2942f999a67Sdrh */ 2952f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 2962f999a67Sdrh static struct { 2972f999a67Sdrh char *zName; 2982f999a67Sdrh Tcl_ObjCmdProc *xProc; 2992f999a67Sdrh } aObjCmd[] = { 3002f999a67Sdrh { "sqlite3_malloc", test_malloc }, 3012f999a67Sdrh { "sqlite3_realloc", test_realloc }, 3022f999a67Sdrh { "sqlite3_free", test_free }, 3032f999a67Sdrh { "sqlite3_memory_used", test_memory_used }, 3042f999a67Sdrh { "sqlite3_memory_highwater", test_memory_highwater }, 3052f999a67Sdrh { "sqlite3_memdebug_backtrace", test_memdebug_backtrace }, 3062f999a67Sdrh { "sqlite3_memdebug_dump", test_memdebug_dump }, 3070e6f1546Sdrh { "sqlite3_memdebug_fail", test_memdebug_fail }, 308*ed138fb3Sdrh { "sqlite3_memdebug_pending", test_memdebug_pending }, 3092f999a67Sdrh }; 3102f999a67Sdrh int i; 3112f999a67Sdrh for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 3122f999a67Sdrh Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 3132f999a67Sdrh } 3142f999a67Sdrh return TCL_OK; 3152f999a67Sdrh } 316