1*2f999a67Sdrh /* 2*2f999a67Sdrh ** 2007 August 15 3*2f999a67Sdrh ** 4*2f999a67Sdrh ** The author disclaims copyright to this source code. In place of 5*2f999a67Sdrh ** a legal notice, here is a blessing: 6*2f999a67Sdrh ** 7*2f999a67Sdrh ** May you do good and not evil. 8*2f999a67Sdrh ** May you find forgiveness for yourself and forgive others. 9*2f999a67Sdrh ** May you share freely, never taking more than you give. 10*2f999a67Sdrh ** 11*2f999a67Sdrh ************************************************************************* 12*2f999a67Sdrh ** 13*2f999a67Sdrh ** This file contains code used to implement test interfaces to the 14*2f999a67Sdrh ** memory allocation subsystem. 15*2f999a67Sdrh ** 16*2f999a67Sdrh ** $Id: test_malloc.c,v 1.1 2007/08/15 19:16:43 drh Exp $ 17*2f999a67Sdrh */ 18*2f999a67Sdrh #include "sqliteInt.h" 19*2f999a67Sdrh #include "tcl.h" 20*2f999a67Sdrh #include <stdlib.h> 21*2f999a67Sdrh #include <string.h> 22*2f999a67Sdrh #include <assert.h> 23*2f999a67Sdrh 24*2f999a67Sdrh /* 25*2f999a67Sdrh ** Transform pointers to text and back again 26*2f999a67Sdrh */ 27*2f999a67Sdrh static void pointerToText(void *p, char *z){ 28*2f999a67Sdrh static const char zHex[] = "0123456789abcdef"; 29*2f999a67Sdrh int i, k; 30*2f999a67Sdrh sqlite3_uint64 n = (sqlite3_uint64)p; 31*2f999a67Sdrh for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 32*2f999a67Sdrh z[k] = zHex[n&0xf]; 33*2f999a67Sdrh n >>= 4; 34*2f999a67Sdrh } 35*2f999a67Sdrh z[sizeof(p)*2] = 0; 36*2f999a67Sdrh } 37*2f999a67Sdrh static int hexToInt(int h){ 38*2f999a67Sdrh if( h>='0' && h<='9' ){ 39*2f999a67Sdrh return h - '0'; 40*2f999a67Sdrh }else if( h>='a' && h<='f' ){ 41*2f999a67Sdrh return h - 'a' + 10; 42*2f999a67Sdrh }else{ 43*2f999a67Sdrh return -1; 44*2f999a67Sdrh } 45*2f999a67Sdrh } 46*2f999a67Sdrh static int textToPointer(const char *z, void **pp){ 47*2f999a67Sdrh sqlite3_uint64 n = 0; 48*2f999a67Sdrh int i; 49*2f999a67Sdrh for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 50*2f999a67Sdrh int v; 51*2f999a67Sdrh v = hexToInt(*z++); 52*2f999a67Sdrh if( v<0 ) return TCL_ERROR; 53*2f999a67Sdrh n = n*16 + v; 54*2f999a67Sdrh } 55*2f999a67Sdrh if( *z!=0 ) return TCL_ERROR; 56*2f999a67Sdrh *pp = (void*)n; 57*2f999a67Sdrh return TCL_OK; 58*2f999a67Sdrh } 59*2f999a67Sdrh 60*2f999a67Sdrh /* 61*2f999a67Sdrh ** Usage: sqlite3_malloc NBYTES 62*2f999a67Sdrh ** 63*2f999a67Sdrh ** Raw test interface for sqlite3_malloc(). 64*2f999a67Sdrh */ 65*2f999a67Sdrh static int test_malloc( 66*2f999a67Sdrh void * clientData, 67*2f999a67Sdrh Tcl_Interp *interp, 68*2f999a67Sdrh int objc, 69*2f999a67Sdrh Tcl_Obj *CONST objv[] 70*2f999a67Sdrh ){ 71*2f999a67Sdrh int nByte; 72*2f999a67Sdrh void *p; 73*2f999a67Sdrh char zOut[100]; 74*2f999a67Sdrh if( objc!=2 ){ 75*2f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 76*2f999a67Sdrh return TCL_ERROR; 77*2f999a67Sdrh } 78*2f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 79*2f999a67Sdrh p = sqlite3_malloc((unsigned)nByte); 80*2f999a67Sdrh pointerToText(p, zOut); 81*2f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 82*2f999a67Sdrh return TCL_OK; 83*2f999a67Sdrh } 84*2f999a67Sdrh 85*2f999a67Sdrh /* 86*2f999a67Sdrh ** Usage: sqlite3_realloc PRIOR NBYTES 87*2f999a67Sdrh ** 88*2f999a67Sdrh ** Raw test interface for sqlite3_realloc(). 89*2f999a67Sdrh */ 90*2f999a67Sdrh static int test_realloc( 91*2f999a67Sdrh void * clientData, 92*2f999a67Sdrh Tcl_Interp *interp, 93*2f999a67Sdrh int objc, 94*2f999a67Sdrh Tcl_Obj *CONST objv[] 95*2f999a67Sdrh ){ 96*2f999a67Sdrh int nByte; 97*2f999a67Sdrh void *pPrior, *p; 98*2f999a67Sdrh char zOut[100]; 99*2f999a67Sdrh if( objc!=3 ){ 100*2f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 101*2f999a67Sdrh return TCL_ERROR; 102*2f999a67Sdrh } 103*2f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 104*2f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 105*2f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 106*2f999a67Sdrh return TCL_ERROR; 107*2f999a67Sdrh } 108*2f999a67Sdrh p = sqlite3_realloc(pPrior, (unsigned)nByte); 109*2f999a67Sdrh pointerToText(p, zOut); 110*2f999a67Sdrh Tcl_AppendResult(interp, zOut, NULL); 111*2f999a67Sdrh return TCL_OK; 112*2f999a67Sdrh } 113*2f999a67Sdrh 114*2f999a67Sdrh 115*2f999a67Sdrh /* 116*2f999a67Sdrh ** Usage: sqlite3_free PRIOR 117*2f999a67Sdrh ** 118*2f999a67Sdrh ** Raw test interface for sqlite3_free(). 119*2f999a67Sdrh */ 120*2f999a67Sdrh static int test_free( 121*2f999a67Sdrh void * clientData, 122*2f999a67Sdrh Tcl_Interp *interp, 123*2f999a67Sdrh int objc, 124*2f999a67Sdrh Tcl_Obj *CONST objv[] 125*2f999a67Sdrh ){ 126*2f999a67Sdrh void *pPrior; 127*2f999a67Sdrh if( objc!=2 ){ 128*2f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 129*2f999a67Sdrh return TCL_ERROR; 130*2f999a67Sdrh } 131*2f999a67Sdrh if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 132*2f999a67Sdrh Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 133*2f999a67Sdrh return TCL_ERROR; 134*2f999a67Sdrh } 135*2f999a67Sdrh sqlite3_free(pPrior); 136*2f999a67Sdrh return TCL_OK; 137*2f999a67Sdrh } 138*2f999a67Sdrh 139*2f999a67Sdrh /* 140*2f999a67Sdrh ** Usage: sqlite3_memory_used 141*2f999a67Sdrh ** 142*2f999a67Sdrh ** Raw test interface for sqlite3_memory_used(). 143*2f999a67Sdrh */ 144*2f999a67Sdrh static int test_memory_used( 145*2f999a67Sdrh void * clientData, 146*2f999a67Sdrh Tcl_Interp *interp, 147*2f999a67Sdrh int objc, 148*2f999a67Sdrh Tcl_Obj *CONST objv[] 149*2f999a67Sdrh ){ 150*2f999a67Sdrh Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 151*2f999a67Sdrh return TCL_OK; 152*2f999a67Sdrh } 153*2f999a67Sdrh 154*2f999a67Sdrh /* 155*2f999a67Sdrh ** Usage: sqlite3_memory_highwater ?RESETFLAG? 156*2f999a67Sdrh ** 157*2f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater(). 158*2f999a67Sdrh */ 159*2f999a67Sdrh static int test_memory_highwater( 160*2f999a67Sdrh void * clientData, 161*2f999a67Sdrh Tcl_Interp *interp, 162*2f999a67Sdrh int objc, 163*2f999a67Sdrh Tcl_Obj *CONST objv[] 164*2f999a67Sdrh ){ 165*2f999a67Sdrh int resetFlag = 0; 166*2f999a67Sdrh if( objc!=1 && objc!=2 ){ 167*2f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 168*2f999a67Sdrh return TCL_ERROR; 169*2f999a67Sdrh } 170*2f999a67Sdrh if( objc==2 ){ 171*2f999a67Sdrh if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 172*2f999a67Sdrh } 173*2f999a67Sdrh Tcl_SetObjResult(interp, 174*2f999a67Sdrh Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 175*2f999a67Sdrh return TCL_OK; 176*2f999a67Sdrh } 177*2f999a67Sdrh 178*2f999a67Sdrh /* 179*2f999a67Sdrh ** Usage: sqlite3_memdebug_backtrace DEPTH 180*2f999a67Sdrh ** 181*2f999a67Sdrh ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 182*2f999a67Sdrh ** then this routine is a no-op. 183*2f999a67Sdrh */ 184*2f999a67Sdrh static int test_memdebug_backtrace( 185*2f999a67Sdrh void * clientData, 186*2f999a67Sdrh Tcl_Interp *interp, 187*2f999a67Sdrh int objc, 188*2f999a67Sdrh Tcl_Obj *CONST objv[] 189*2f999a67Sdrh ){ 190*2f999a67Sdrh int depth; 191*2f999a67Sdrh if( objc!=2 ){ 192*2f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 193*2f999a67Sdrh return TCL_ERROR; 194*2f999a67Sdrh } 195*2f999a67Sdrh if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 196*2f999a67Sdrh #ifdef SQLITE_MEMDEBUG 197*2f999a67Sdrh { 198*2f999a67Sdrh extern void sqlite3_memdebug_backtrace(int); 199*2f999a67Sdrh sqlite3_memdebug_backtrace(depth); 200*2f999a67Sdrh } 201*2f999a67Sdrh #endif 202*2f999a67Sdrh return TCL_OK; 203*2f999a67Sdrh } 204*2f999a67Sdrh 205*2f999a67Sdrh /* 206*2f999a67Sdrh ** Usage: sqlite3_memdebug_dump FILENAME 207*2f999a67Sdrh ** 208*2f999a67Sdrh ** Write a summary of unfreed memory to FILENAME. 209*2f999a67Sdrh */ 210*2f999a67Sdrh static int test_memdebug_dump( 211*2f999a67Sdrh void * clientData, 212*2f999a67Sdrh Tcl_Interp *interp, 213*2f999a67Sdrh int objc, 214*2f999a67Sdrh Tcl_Obj *CONST objv[] 215*2f999a67Sdrh ){ 216*2f999a67Sdrh if( objc!=2 ){ 217*2f999a67Sdrh Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 218*2f999a67Sdrh return TCL_ERROR; 219*2f999a67Sdrh } 220*2f999a67Sdrh #ifdef SQLITE_MEMDEBUG 221*2f999a67Sdrh { 222*2f999a67Sdrh extern void sqlite3_memdebug_dump(const char*); 223*2f999a67Sdrh sqlite3_memdebug_dump(Tcl_GetString(objv[1])); 224*2f999a67Sdrh } 225*2f999a67Sdrh #endif 226*2f999a67Sdrh return TCL_OK; 227*2f999a67Sdrh } 228*2f999a67Sdrh 229*2f999a67Sdrh 230*2f999a67Sdrh /* 231*2f999a67Sdrh ** Register commands with the TCL interpreter. 232*2f999a67Sdrh */ 233*2f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 234*2f999a67Sdrh static struct { 235*2f999a67Sdrh char *zName; 236*2f999a67Sdrh Tcl_ObjCmdProc *xProc; 237*2f999a67Sdrh } aObjCmd[] = { 238*2f999a67Sdrh { "sqlite3_malloc", test_malloc }, 239*2f999a67Sdrh { "sqlite3_realloc", test_realloc }, 240*2f999a67Sdrh { "sqlite3_free", test_free }, 241*2f999a67Sdrh { "sqlite3_memory_used", test_memory_used }, 242*2f999a67Sdrh { "sqlite3_memory_highwater", test_memory_highwater }, 243*2f999a67Sdrh { "sqlite3_memdebug_backtrace", test_memdebug_backtrace }, 244*2f999a67Sdrh { "sqlite3_memdebug_dump", test_memdebug_dump }, 245*2f999a67Sdrh }; 246*2f999a67Sdrh int i; 247*2f999a67Sdrh for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 248*2f999a67Sdrh Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 249*2f999a67Sdrh } 250*2f999a67Sdrh return TCL_OK; 251*2f999a67Sdrh } 252