1 /* 2 ** 2007 August 15 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** 13 ** This file contains code used to implement test interfaces to the 14 ** memory allocation subsystem. 15 ** 16 ** $Id: test_malloc.c,v 1.5 2007/08/24 03:51:34 drh Exp $ 17 */ 18 #include "sqliteInt.h" 19 #include "tcl.h" 20 #include <stdlib.h> 21 #include <string.h> 22 #include <assert.h> 23 24 /* 25 ** Transform pointers to text and back again 26 */ 27 static void pointerToText(void *p, char *z){ 28 static const char zHex[] = "0123456789abcdef"; 29 int i, k; 30 unsigned int u; 31 sqlite3_uint64 n; 32 if( sizeof(n)==sizeof(p) ){ 33 memcpy(&n, &p, sizeof(p)); 34 }else if( sizeof(u)==sizeof(p) ){ 35 memcpy(&u, &p, sizeof(u)); 36 n = u; 37 }else{ 38 assert( 0 ); 39 } 40 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 41 z[k] = zHex[n&0xf]; 42 n >>= 4; 43 } 44 z[sizeof(p)*2] = 0; 45 } 46 static int hexToInt(int h){ 47 if( h>='0' && h<='9' ){ 48 return h - '0'; 49 }else if( h>='a' && h<='f' ){ 50 return h - 'a' + 10; 51 }else{ 52 return -1; 53 } 54 } 55 static int textToPointer(const char *z, void **pp){ 56 sqlite3_uint64 n = 0; 57 int i; 58 unsigned int u; 59 for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 60 int v; 61 v = hexToInt(*z++); 62 if( v<0 ) return TCL_ERROR; 63 n = n*16 + v; 64 } 65 if( *z!=0 ) return TCL_ERROR; 66 if( sizeof(n)==sizeof(*pp) ){ 67 memcpy(pp, &n, sizeof(n)); 68 }else if( sizeof(u)==sizeof(*pp) ){ 69 u = (unsigned int)n; 70 memcpy(pp, &u, sizeof(u)); 71 }else{ 72 assert( 0 ); 73 } 74 return TCL_OK; 75 } 76 77 /* 78 ** Usage: sqlite3_malloc NBYTES 79 ** 80 ** Raw test interface for sqlite3_malloc(). 81 */ 82 static int test_malloc( 83 void * clientData, 84 Tcl_Interp *interp, 85 int objc, 86 Tcl_Obj *CONST objv[] 87 ){ 88 int nByte; 89 void *p; 90 char zOut[100]; 91 if( objc!=2 ){ 92 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 93 return TCL_ERROR; 94 } 95 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 96 p = sqlite3_malloc((unsigned)nByte); 97 pointerToText(p, zOut); 98 Tcl_AppendResult(interp, zOut, NULL); 99 return TCL_OK; 100 } 101 102 /* 103 ** Usage: sqlite3_realloc PRIOR NBYTES 104 ** 105 ** Raw test interface for sqlite3_realloc(). 106 */ 107 static int test_realloc( 108 void * clientData, 109 Tcl_Interp *interp, 110 int objc, 111 Tcl_Obj *CONST objv[] 112 ){ 113 int nByte; 114 void *pPrior, *p; 115 char zOut[100]; 116 if( objc!=3 ){ 117 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 118 return TCL_ERROR; 119 } 120 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 121 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 122 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 123 return TCL_ERROR; 124 } 125 p = sqlite3_realloc(pPrior, (unsigned)nByte); 126 pointerToText(p, zOut); 127 Tcl_AppendResult(interp, zOut, NULL); 128 return TCL_OK; 129 } 130 131 132 /* 133 ** Usage: sqlite3_free PRIOR 134 ** 135 ** Raw test interface for sqlite3_free(). 136 */ 137 static int test_free( 138 void * clientData, 139 Tcl_Interp *interp, 140 int objc, 141 Tcl_Obj *CONST objv[] 142 ){ 143 void *pPrior; 144 if( objc!=2 ){ 145 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 146 return TCL_ERROR; 147 } 148 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 149 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 150 return TCL_ERROR; 151 } 152 sqlite3_free(pPrior); 153 return TCL_OK; 154 } 155 156 /* 157 ** Usage: sqlite3_memory_used 158 ** 159 ** Raw test interface for sqlite3_memory_used(). 160 */ 161 static int test_memory_used( 162 void * clientData, 163 Tcl_Interp *interp, 164 int objc, 165 Tcl_Obj *CONST objv[] 166 ){ 167 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 168 return TCL_OK; 169 } 170 171 /* 172 ** Usage: sqlite3_memory_highwater ?RESETFLAG? 173 ** 174 ** Raw test interface for sqlite3_memory_highwater(). 175 */ 176 static int test_memory_highwater( 177 void * clientData, 178 Tcl_Interp *interp, 179 int objc, 180 Tcl_Obj *CONST objv[] 181 ){ 182 int resetFlag = 0; 183 if( objc!=1 && objc!=2 ){ 184 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 185 return TCL_ERROR; 186 } 187 if( objc==2 ){ 188 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 189 } 190 Tcl_SetObjResult(interp, 191 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 192 return TCL_OK; 193 } 194 195 /* 196 ** Usage: sqlite3_memdebug_backtrace DEPTH 197 ** 198 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 199 ** then this routine is a no-op. 200 */ 201 static int test_memdebug_backtrace( 202 void * clientData, 203 Tcl_Interp *interp, 204 int objc, 205 Tcl_Obj *CONST objv[] 206 ){ 207 int depth; 208 if( objc!=2 ){ 209 Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 210 return TCL_ERROR; 211 } 212 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 213 #ifdef SQLITE_MEMDEBUG 214 { 215 extern void sqlite3_memdebug_backtrace(int); 216 sqlite3_memdebug_backtrace(depth); 217 } 218 #endif 219 return TCL_OK; 220 } 221 222 /* 223 ** Usage: sqlite3_memdebug_dump FILENAME 224 ** 225 ** Write a summary of unfreed memory to FILENAME. 226 */ 227 static int test_memdebug_dump( 228 void * clientData, 229 Tcl_Interp *interp, 230 int objc, 231 Tcl_Obj *CONST objv[] 232 ){ 233 if( objc!=2 ){ 234 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 235 return TCL_ERROR; 236 } 237 #ifdef SQLITE_MEMDEBUG 238 { 239 extern void sqlite3_memdebug_dump(const char*); 240 sqlite3_memdebug_dump(Tcl_GetString(objv[1])); 241 } 242 #endif 243 return TCL_OK; 244 } 245 246 247 /* 248 ** Usage: sqlite3_memdebug_fail COUNTER ?REPEAT? 249 ** 250 ** Arrange for a simulated malloc() failure after COUNTER successes. 251 ** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is 252 ** 0 then only a single failure occurs. 253 ** 254 ** Each call to this routine overrides the prior counter value. 255 ** This routine returns the number of simulated failures that have 256 ** happened since the previous call to this routine. 257 ** 258 ** To disable simulated failures, use a COUNTER of -1. 259 */ 260 static int test_memdebug_fail( 261 void * clientData, 262 Tcl_Interp *interp, 263 int objc, 264 Tcl_Obj *CONST objv[] 265 ){ 266 int iFail; 267 int iRepeat; 268 int nFail = 0; 269 if( objc!=3 && objc!=2 ){ 270 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?REPEAT?"); 271 return TCL_ERROR; 272 } 273 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 274 if( objc==3 ){ 275 if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR; 276 }else{ 277 iRepeat = -1; 278 } 279 #ifdef SQLITE_MEMDEBUG 280 { 281 extern int sqlite3_memdebug_fail(int,int); 282 nFail = sqlite3_memdebug_fail(iFail, iRepeat); 283 } 284 #endif 285 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 286 return TCL_OK; 287 } 288 289 290 /* 291 ** Usage: sqlite3_memdebug_settitle TITLE 292 ** 293 ** Set a title string stored with each allocation. The TITLE is 294 ** typically the name of the test that was running when the 295 ** allocation occurred. The TITLE is stored with the allocation 296 ** and can be used to figure out which tests are leaking memory. 297 ** 298 ** Each title overwrite the previous. 299 */ 300 static int test_memdebug_settitle( 301 void * clientData, 302 Tcl_Interp *interp, 303 int objc, 304 Tcl_Obj *CONST objv[] 305 ){ 306 const char *zTitle; 307 if( objc!=2 ){ 308 Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); 309 return TCL_ERROR; 310 } 311 zTitle = Tcl_GetString(objv[1]); 312 #ifdef SQLITE_MEMDEBUG 313 { 314 extern int sqlite3_memdebug_settitle(const char*); 315 sqlite3_memdebug_settitle(zTitle); 316 } 317 #endif 318 return TCL_OK; 319 } 320 321 322 /* 323 ** Register commands with the TCL interpreter. 324 */ 325 int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 326 static struct { 327 char *zName; 328 Tcl_ObjCmdProc *xProc; 329 } aObjCmd[] = { 330 { "sqlite3_malloc", test_malloc }, 331 { "sqlite3_realloc", test_realloc }, 332 { "sqlite3_free", test_free }, 333 { "sqlite3_memory_used", test_memory_used }, 334 { "sqlite3_memory_highwater", test_memory_highwater }, 335 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace }, 336 { "sqlite3_memdebug_dump", test_memdebug_dump }, 337 { "sqlite3_memdebug_fail", test_memdebug_fail }, 338 { "sqlite3_memdebug_settitle", test_memdebug_settitle }, 339 }; 340 int i; 341 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 342 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 343 } 344 return TCL_OK; 345 } 346