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.38 2008/07/16 12:25:32 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 ** This structure is used to encapsulate the global state variables used 26 ** by malloc() fault simulation. 27 */ 28 static struct MemFault { 29 int iCountdown; /* Number of pending successes before a failure */ 30 int nRepeat; /* Number of times to repeat the failure */ 31 int nBenign; /* Number of benign failures seen since last config */ 32 int nFail; /* Number of failures seen since last config */ 33 u8 enable; /* True if enabled */ 34 int isInstalled; /* True if the fault simulation layer is installed */ 35 int isBenignMode; /* True if malloc failures are considered benign */ 36 sqlite3_mem_methods m; /* 'Real' malloc implementation */ 37 } memfault; 38 39 /* 40 ** This routine exists as a place to set a breakpoint that will 41 ** fire on any simulated malloc() failure. 42 */ 43 static void sqlite3Fault(void){ 44 static int cnt = 0; 45 cnt++; 46 } 47 48 /* 49 ** Check to see if a fault should be simulated. Return true to simulate 50 ** the fault. Return false if the fault should not be simulated. 51 */ 52 static int faultsimStep(){ 53 if( likely(!memfault.enable) ){ 54 return 0; 55 } 56 if( memfault.iCountdown>0 ){ 57 memfault.iCountdown--; 58 return 0; 59 } 60 sqlite3Fault(); 61 memfault.nFail++; 62 if( memfault.isBenignMode>0 ){ 63 memfault.nBenign++; 64 } 65 memfault.nRepeat--; 66 if( memfault.nRepeat<=0 ){ 67 memfault.enable = 0; 68 } 69 return 1; 70 } 71 72 /* 73 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation 74 ** logic. 75 */ 76 static void *faultsimMalloc(int n){ 77 void *p = 0; 78 if( !faultsimStep() ){ 79 p = memfault.m.xMalloc(n); 80 } 81 return p; 82 } 83 84 85 /* 86 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation 87 ** logic. 88 */ 89 static void *faultsimRealloc(void *pOld, int n){ 90 void *p = 0; 91 if( !faultsimStep() ){ 92 p = memfault.m.xRealloc(pOld, n); 93 } 94 return p; 95 } 96 97 /* 98 ** The following method calls are passed directly through to the underlying 99 ** malloc system: 100 ** 101 ** xFree 102 ** xSize 103 ** xRoundup 104 ** xInit 105 ** xShutdown 106 */ 107 static void faultsimFree(void *p){ 108 memfault.m.xFree(p); 109 } 110 static int faultsimSize(void *p){ 111 return memfault.m.xSize(p); 112 } 113 static int faultsimRoundup(int n){ 114 return memfault.m.xRoundup(n); 115 } 116 static int faultsimInit(void *p){ 117 return memfault.m.xInit(memfault.m.pAppData); 118 } 119 static void faultsimShutdown(void *p){ 120 memfault.m.xShutdown(memfault.m.pAppData); 121 } 122 123 /* 124 ** This routine configures the malloc failure simulation. After 125 ** calling this routine, the next nDelay mallocs will succeed, followed 126 ** by a block of nRepeat failures, after which malloc() calls will begin 127 ** to succeed again. 128 */ 129 static void faultsimConfig(int nDelay, int nRepeat){ 130 memfault.iCountdown = nDelay; 131 memfault.nRepeat = nRepeat; 132 memfault.nBenign = 0; 133 memfault.nFail = 0; 134 memfault.enable = nDelay>=0; 135 } 136 137 /* 138 ** Return the number of faults (both hard and benign faults) that have 139 ** occurred since the injector was last configured. 140 */ 141 static int faultsimFailures(void){ 142 return memfault.nFail; 143 } 144 145 /* 146 ** Return the number of benign faults that have occurred since the 147 ** injector was last configured. 148 */ 149 static int faultsimBenignFailures(void){ 150 return memfault.nBenign; 151 } 152 153 /* 154 ** Return the number of successes that will occur before the next failure. 155 ** If no failures are scheduled, return -1. 156 */ 157 static int faultsimPending(void){ 158 if( memfault.enable ){ 159 return memfault.iCountdown; 160 }else{ 161 return -1; 162 } 163 } 164 165 166 static void faultsimBeginBenign(void){ 167 memfault.isBenignMode++; 168 } 169 static void faultsimEndBenign(void){ 170 memfault.isBenignMode--; 171 } 172 173 /* 174 ** Add or remove the fault-simulation layer using sqlite3_config(). If 175 ** the argument is non-zero, the 176 */ 177 static int faultsimInstall(int install){ 178 static struct sqlite3_mem_methods m = { 179 faultsimMalloc, /* xMalloc */ 180 faultsimFree, /* xFree */ 181 faultsimRealloc, /* xRealloc */ 182 faultsimSize, /* xSize */ 183 faultsimRoundup, /* xRoundup */ 184 faultsimInit, /* xInit */ 185 faultsimShutdown, /* xShutdown */ 186 0 /* pAppData */ 187 }; 188 int rc; 189 190 install = (install ? 1 : 0); 191 assert(memfault.isInstalled==1 || memfault.isInstalled==0); 192 193 if( install==memfault.isInstalled ){ 194 return SQLITE_ERROR; 195 } 196 197 if( install ){ 198 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m); 199 assert(memfault.m.xMalloc); 200 if( rc==SQLITE_OK ){ 201 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); 202 } 203 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 204 faultsimBeginBenign, faultsimEndBenign 205 ); 206 }else{ 207 assert(memfault.m.xMalloc); 208 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m); 209 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0); 210 } 211 212 if( rc==SQLITE_OK ){ 213 memfault.isInstalled = 1; 214 } 215 return rc; 216 } 217 218 #ifdef SQLITE_TEST 219 220 /* 221 ** This function is implemented in test1.c. Returns a pointer to a static 222 ** buffer containing the symbolic SQLite error code that corresponds to 223 ** the least-significant 8-bits of the integer passed as an argument. 224 ** For example: 225 ** 226 ** sqlite3TestErrorName(1) -> "SQLITE_ERROR" 227 */ 228 const char *sqlite3TestErrorName(int); 229 230 /* 231 ** Transform pointers to text and back again 232 */ 233 static void pointerToText(void *p, char *z){ 234 static const char zHex[] = "0123456789abcdef"; 235 int i, k; 236 unsigned int u; 237 sqlite3_uint64 n; 238 if( p==0 ){ 239 strcpy(z, "0"); 240 return; 241 } 242 if( sizeof(n)==sizeof(p) ){ 243 memcpy(&n, &p, sizeof(p)); 244 }else if( sizeof(u)==sizeof(p) ){ 245 memcpy(&u, &p, sizeof(u)); 246 n = u; 247 }else{ 248 assert( 0 ); 249 } 250 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 251 z[k] = zHex[n&0xf]; 252 n >>= 4; 253 } 254 z[sizeof(p)*2] = 0; 255 } 256 static int hexToInt(int h){ 257 if( h>='0' && h<='9' ){ 258 return h - '0'; 259 }else if( h>='a' && h<='f' ){ 260 return h - 'a' + 10; 261 }else{ 262 return -1; 263 } 264 } 265 static int textToPointer(const char *z, void **pp){ 266 sqlite3_uint64 n = 0; 267 int i; 268 unsigned int u; 269 for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 270 int v; 271 v = hexToInt(*z++); 272 if( v<0 ) return TCL_ERROR; 273 n = n*16 + v; 274 } 275 if( *z!=0 ) return TCL_ERROR; 276 if( sizeof(n)==sizeof(*pp) ){ 277 memcpy(pp, &n, sizeof(n)); 278 }else if( sizeof(u)==sizeof(*pp) ){ 279 u = (unsigned int)n; 280 memcpy(pp, &u, sizeof(u)); 281 }else{ 282 assert( 0 ); 283 } 284 return TCL_OK; 285 } 286 287 /* 288 ** Usage: sqlite3_malloc NBYTES 289 ** 290 ** Raw test interface for sqlite3_malloc(). 291 */ 292 static int test_malloc( 293 void * clientData, 294 Tcl_Interp *interp, 295 int objc, 296 Tcl_Obj *CONST objv[] 297 ){ 298 int nByte; 299 void *p; 300 char zOut[100]; 301 if( objc!=2 ){ 302 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 303 return TCL_ERROR; 304 } 305 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 306 p = sqlite3_malloc((unsigned)nByte); 307 pointerToText(p, zOut); 308 Tcl_AppendResult(interp, zOut, NULL); 309 return TCL_OK; 310 } 311 312 /* 313 ** Usage: sqlite3_realloc PRIOR NBYTES 314 ** 315 ** Raw test interface for sqlite3_realloc(). 316 */ 317 static int test_realloc( 318 void * clientData, 319 Tcl_Interp *interp, 320 int objc, 321 Tcl_Obj *CONST objv[] 322 ){ 323 int nByte; 324 void *pPrior, *p; 325 char zOut[100]; 326 if( objc!=3 ){ 327 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 328 return TCL_ERROR; 329 } 330 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 331 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 332 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 333 return TCL_ERROR; 334 } 335 p = sqlite3_realloc(pPrior, (unsigned)nByte); 336 pointerToText(p, zOut); 337 Tcl_AppendResult(interp, zOut, NULL); 338 return TCL_OK; 339 } 340 341 /* 342 ** Usage: sqlite3_free PRIOR 343 ** 344 ** Raw test interface for sqlite3_free(). 345 */ 346 static int test_free( 347 void * clientData, 348 Tcl_Interp *interp, 349 int objc, 350 Tcl_Obj *CONST objv[] 351 ){ 352 void *pPrior; 353 if( objc!=2 ){ 354 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 355 return TCL_ERROR; 356 } 357 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 358 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 359 return TCL_ERROR; 360 } 361 sqlite3_free(pPrior); 362 return TCL_OK; 363 } 364 365 /* 366 ** These routines are in test_hexio.c 367 */ 368 int sqlite3TestHexToBin(const char *, int, char *); 369 int sqlite3TestBinToHex(char*,int); 370 371 /* 372 ** Usage: memset ADDRESS SIZE HEX 373 ** 374 ** Set a chunk of memory (obtained from malloc, probably) to a 375 ** specified hex pattern. 376 */ 377 static int test_memset( 378 void * clientData, 379 Tcl_Interp *interp, 380 int objc, 381 Tcl_Obj *CONST objv[] 382 ){ 383 void *p; 384 int size, n, i; 385 char *zHex; 386 char *zOut; 387 char zBin[100]; 388 389 if( objc!=4 ){ 390 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX"); 391 return TCL_ERROR; 392 } 393 if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 394 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 395 return TCL_ERROR; 396 } 397 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 398 return TCL_ERROR; 399 } 400 if( size<=0 ){ 401 Tcl_AppendResult(interp, "size must be positive", (char*)0); 402 return TCL_ERROR; 403 } 404 zHex = Tcl_GetStringFromObj(objv[3], &n); 405 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2; 406 n = sqlite3TestHexToBin(zHex, n, zBin); 407 if( n==0 ){ 408 Tcl_AppendResult(interp, "no data", (char*)0); 409 return TCL_ERROR; 410 } 411 zOut = p; 412 for(i=0; i<size; i++){ 413 zOut[i] = zBin[i%n]; 414 } 415 return TCL_OK; 416 } 417 418 /* 419 ** Usage: memget ADDRESS SIZE 420 ** 421 ** Return memory as hexadecimal text. 422 */ 423 static int test_memget( 424 void * clientData, 425 Tcl_Interp *interp, 426 int objc, 427 Tcl_Obj *CONST objv[] 428 ){ 429 void *p; 430 int size, n; 431 char *zBin; 432 char zHex[100]; 433 434 if( objc!=3 ){ 435 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE"); 436 return TCL_ERROR; 437 } 438 if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 439 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 440 return TCL_ERROR; 441 } 442 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 443 return TCL_ERROR; 444 } 445 if( size<=0 ){ 446 Tcl_AppendResult(interp, "size must be positive", (char*)0); 447 return TCL_ERROR; 448 } 449 zBin = p; 450 while( size>0 ){ 451 if( size>(sizeof(zHex)-1)/2 ){ 452 n = (sizeof(zHex)-1)/2; 453 }else{ 454 n = size; 455 } 456 memcpy(zHex, zBin, n); 457 zBin += n; 458 size -= n; 459 sqlite3TestBinToHex(zHex, n); 460 Tcl_AppendResult(interp, zHex, (char*)0); 461 } 462 return TCL_OK; 463 } 464 465 /* 466 ** Usage: sqlite3_memory_used 467 ** 468 ** Raw test interface for sqlite3_memory_used(). 469 */ 470 static int test_memory_used( 471 void * clientData, 472 Tcl_Interp *interp, 473 int objc, 474 Tcl_Obj *CONST objv[] 475 ){ 476 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 477 return TCL_OK; 478 } 479 480 /* 481 ** Usage: sqlite3_memory_highwater ?RESETFLAG? 482 ** 483 ** Raw test interface for sqlite3_memory_highwater(). 484 */ 485 static int test_memory_highwater( 486 void * clientData, 487 Tcl_Interp *interp, 488 int objc, 489 Tcl_Obj *CONST objv[] 490 ){ 491 int resetFlag = 0; 492 if( objc!=1 && objc!=2 ){ 493 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 494 return TCL_ERROR; 495 } 496 if( objc==2 ){ 497 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 498 } 499 Tcl_SetObjResult(interp, 500 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 501 return TCL_OK; 502 } 503 504 /* 505 ** Usage: sqlite3_memdebug_backtrace DEPTH 506 ** 507 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 508 ** then this routine is a no-op. 509 */ 510 static int test_memdebug_backtrace( 511 void * clientData, 512 Tcl_Interp *interp, 513 int objc, 514 Tcl_Obj *CONST objv[] 515 ){ 516 int depth; 517 if( objc!=2 ){ 518 Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 519 return TCL_ERROR; 520 } 521 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 522 #ifdef SQLITE_MEMDEBUG 523 { 524 extern void sqlite3MemdebugBacktrace(int); 525 sqlite3MemdebugBacktrace(depth); 526 } 527 #endif 528 return TCL_OK; 529 } 530 531 /* 532 ** Usage: sqlite3_memdebug_dump FILENAME 533 ** 534 ** Write a summary of unfreed memory to FILENAME. 535 */ 536 static int test_memdebug_dump( 537 void * clientData, 538 Tcl_Interp *interp, 539 int objc, 540 Tcl_Obj *CONST objv[] 541 ){ 542 if( objc!=2 ){ 543 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 544 return TCL_ERROR; 545 } 546 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ 547 || defined(SQLITE_POW2_MEMORY_SIZE) 548 { 549 extern void sqlite3MemdebugDump(const char*); 550 sqlite3MemdebugDump(Tcl_GetString(objv[1])); 551 } 552 #endif 553 return TCL_OK; 554 } 555 556 /* 557 ** Usage: sqlite3_memdebug_malloc_count 558 ** 559 ** Return the total number of times malloc() has been called. 560 */ 561 static int test_memdebug_malloc_count( 562 void * clientData, 563 Tcl_Interp *interp, 564 int objc, 565 Tcl_Obj *CONST objv[] 566 ){ 567 int nMalloc = -1; 568 if( objc!=1 ){ 569 Tcl_WrongNumArgs(interp, 1, objv, ""); 570 return TCL_ERROR; 571 } 572 #if defined(SQLITE_MEMDEBUG) 573 { 574 extern int sqlite3MemdebugMallocCount(); 575 nMalloc = sqlite3MemdebugMallocCount(); 576 } 577 #endif 578 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); 579 return TCL_OK; 580 } 581 582 583 /* 584 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? 585 ** 586 ** where options are: 587 ** 588 ** -repeat <count> 589 ** -benigncnt <varname> 590 ** 591 ** Arrange for a simulated malloc() failure after COUNTER successes. 592 ** If a repeat count is specified, the fault is repeated that many 593 ** times. 594 ** 595 ** Each call to this routine overrides the prior counter value. 596 ** This routine returns the number of simulated failures that have 597 ** happened since the previous call to this routine. 598 ** 599 ** To disable simulated failures, use a COUNTER of -1. 600 */ 601 static int test_memdebug_fail( 602 void * clientData, 603 Tcl_Interp *interp, 604 int objc, 605 Tcl_Obj *CONST objv[] 606 ){ 607 int ii; 608 int iFail; 609 int nRepeat = 1; 610 Tcl_Obj *pBenignCnt = 0; 611 int nBenign; 612 int nFail = 0; 613 614 if( objc<2 ){ 615 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); 616 return TCL_ERROR; 617 } 618 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 619 620 for(ii=2; ii<objc; ii+=2){ 621 int nOption; 622 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); 623 char *zErr = 0; 624 625 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ 626 if( ii==(objc-1) ){ 627 zErr = "option requires an argument: "; 628 }else{ 629 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ 630 return TCL_ERROR; 631 } 632 } 633 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ 634 if( ii==(objc-1) ){ 635 zErr = "option requires an argument: "; 636 }else{ 637 pBenignCnt = objv[ii+1]; 638 } 639 }else{ 640 zErr = "unknown option: "; 641 } 642 643 if( zErr ){ 644 Tcl_AppendResult(interp, zErr, zOption, 0); 645 return TCL_ERROR; 646 } 647 } 648 649 nBenign = faultsimBenignFailures(); 650 nFail = faultsimFailures(); 651 faultsimConfig(iFail, nRepeat); 652 653 if( pBenignCnt ){ 654 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); 655 } 656 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 657 return TCL_OK; 658 } 659 660 /* 661 ** Usage: sqlite3_memdebug_pending 662 ** 663 ** Return the number of malloc() calls that will succeed before a 664 ** simulated failure occurs. A negative return value indicates that 665 ** no malloc() failure is scheduled. 666 */ 667 static int test_memdebug_pending( 668 void * clientData, 669 Tcl_Interp *interp, 670 int objc, 671 Tcl_Obj *CONST objv[] 672 ){ 673 int nPending; 674 if( objc!=1 ){ 675 Tcl_WrongNumArgs(interp, 1, objv, ""); 676 return TCL_ERROR; 677 } 678 nPending = faultsimPending(); 679 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending)); 680 return TCL_OK; 681 } 682 683 684 /* 685 ** Usage: sqlite3_memdebug_settitle TITLE 686 ** 687 ** Set a title string stored with each allocation. The TITLE is 688 ** typically the name of the test that was running when the 689 ** allocation occurred. The TITLE is stored with the allocation 690 ** and can be used to figure out which tests are leaking memory. 691 ** 692 ** Each title overwrite the previous. 693 */ 694 static int test_memdebug_settitle( 695 void * clientData, 696 Tcl_Interp *interp, 697 int objc, 698 Tcl_Obj *CONST objv[] 699 ){ 700 const char *zTitle; 701 if( objc!=2 ){ 702 Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); 703 return TCL_ERROR; 704 } 705 zTitle = Tcl_GetString(objv[1]); 706 #ifdef SQLITE_MEMDEBUG 707 { 708 extern int sqlite3MemdebugSettitle(const char*); 709 sqlite3MemdebugSettitle(zTitle); 710 } 711 #endif 712 return TCL_OK; 713 } 714 715 #define MALLOC_LOG_FRAMES 10 716 static Tcl_HashTable aMallocLog; 717 static int mallocLogEnabled = 0; 718 719 typedef struct MallocLog MallocLog; 720 struct MallocLog { 721 int nCall; 722 int nByte; 723 }; 724 725 #ifdef SQLITE_MEMDEBUG 726 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ 727 if( mallocLogEnabled ){ 728 MallocLog *pLog; 729 Tcl_HashEntry *pEntry; 730 int isNew; 731 732 int aKey[MALLOC_LOG_FRAMES]; 733 int nKey = sizeof(int)*MALLOC_LOG_FRAMES; 734 735 memset(aKey, 0, nKey); 736 if( (sizeof(void*)*nFrame)<nKey ){ 737 nKey = nFrame*sizeof(void*); 738 } 739 memcpy(aKey, aFrame, nKey); 740 741 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); 742 if( isNew ){ 743 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); 744 memset(pLog, 0, sizeof(MallocLog)); 745 Tcl_SetHashValue(pEntry, (ClientData)pLog); 746 }else{ 747 pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 748 } 749 750 pLog->nCall++; 751 pLog->nByte += nByte; 752 } 753 } 754 #endif /* SQLITE_MEMDEBUG */ 755 756 static void test_memdebug_log_clear(){ 757 Tcl_HashSearch search; 758 Tcl_HashEntry *pEntry; 759 for( 760 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 761 pEntry; 762 pEntry=Tcl_NextHashEntry(&search) 763 ){ 764 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 765 Tcl_Free((char *)pLog); 766 } 767 Tcl_DeleteHashTable(&aMallocLog); 768 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 769 } 770 771 static int test_memdebug_log( 772 void * clientData, 773 Tcl_Interp *interp, 774 int objc, 775 Tcl_Obj *CONST objv[] 776 ){ 777 static int isInit = 0; 778 int iSub; 779 780 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" }; 781 enum MB_enum { 782 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC 783 }; 784 785 if( !isInit ){ 786 #ifdef SQLITE_MEMDEBUG 787 extern void sqlite3MemdebugBacktraceCallback( 788 void (*xBacktrace)(int, int, void **)); 789 sqlite3MemdebugBacktraceCallback(test_memdebug_callback); 790 #endif 791 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 792 isInit = 1; 793 } 794 795 if( objc<2 ){ 796 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 797 } 798 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ 799 return TCL_ERROR; 800 } 801 802 switch( (enum MB_enum)iSub ){ 803 case MB_LOG_START: 804 mallocLogEnabled = 1; 805 break; 806 case MB_LOG_STOP: 807 mallocLogEnabled = 0; 808 break; 809 case MB_LOG_DUMP: { 810 Tcl_HashSearch search; 811 Tcl_HashEntry *pEntry; 812 Tcl_Obj *pRet = Tcl_NewObj(); 813 814 assert(sizeof(int)==sizeof(void*)); 815 816 for( 817 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 818 pEntry; 819 pEntry=Tcl_NextHashEntry(&search) 820 ){ 821 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; 822 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 823 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry); 824 int ii; 825 826 apElem[0] = Tcl_NewIntObj(pLog->nCall); 827 apElem[1] = Tcl_NewIntObj(pLog->nByte); 828 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ 829 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]); 830 } 831 832 Tcl_ListObjAppendElement(interp, pRet, 833 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) 834 ); 835 } 836 837 Tcl_SetObjResult(interp, pRet); 838 break; 839 } 840 case MB_LOG_CLEAR: { 841 test_memdebug_log_clear(); 842 break; 843 } 844 845 case MB_LOG_SYNC: { 846 #ifdef SQLITE_MEMDEBUG 847 extern void sqlite3MemdebugSync(); 848 test_memdebug_log_clear(); 849 mallocLogEnabled = 1; 850 sqlite3MemdebugSync(); 851 #endif 852 break; 853 } 854 } 855 856 return TCL_OK; 857 } 858 859 /* 860 ** Usage: sqlite3_config_scratch SIZE N 861 ** 862 ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. 863 ** The buffer is static and is of limited size. N might be 864 ** adjusted downward as needed to accomodate the requested size. 865 ** The revised value of N is returned. 866 ** 867 ** A negative SIZE causes the buffer pointer to be NULL. 868 */ 869 static int test_config_scratch( 870 void * clientData, 871 Tcl_Interp *interp, 872 int objc, 873 Tcl_Obj *CONST objv[] 874 ){ 875 int sz, N, rc; 876 Tcl_Obj *pResult; 877 static char buf[30000]; 878 if( objc!=3 ){ 879 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 880 return TCL_ERROR; 881 } 882 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 883 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 884 if( sz<0 ){ 885 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); 886 }else{ 887 int mx = sizeof(buf)/(sz+4); 888 if( N>mx ) N = mx; 889 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); 890 } 891 pResult = Tcl_NewObj(); 892 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 893 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 894 Tcl_SetObjResult(interp, pResult); 895 return TCL_OK; 896 } 897 898 /* 899 ** Usage: sqlite3_config_pagecache SIZE N 900 ** 901 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. 902 ** The buffer is static and is of limited size. N might be 903 ** adjusted downward as needed to accomodate the requested size. 904 ** The revised value of N is returned. 905 ** 906 ** A negative SIZE causes the buffer pointer to be NULL. 907 */ 908 static int test_config_pagecache( 909 void * clientData, 910 Tcl_Interp *interp, 911 int objc, 912 Tcl_Obj *CONST objv[] 913 ){ 914 int sz, N, rc; 915 Tcl_Obj *pResult; 916 static char buf[100000]; 917 if( objc!=3 ){ 918 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 919 return TCL_ERROR; 920 } 921 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 922 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 923 if( sz<0 ){ 924 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); 925 }else{ 926 int mx = sizeof(buf)/(sz+4); 927 if( N>mx ) N = mx; 928 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); 929 } 930 pResult = Tcl_NewObj(); 931 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 932 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 933 Tcl_SetObjResult(interp, pResult); 934 return TCL_OK; 935 } 936 937 /* 938 ** Usage: sqlite3_config_memstatus BOOLEAN 939 ** 940 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. 941 */ 942 static int test_config_memstatus( 943 void * clientData, 944 Tcl_Interp *interp, 945 int objc, 946 Tcl_Obj *CONST objv[] 947 ){ 948 int enable, rc; 949 if( objc!=2 ){ 950 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 951 return TCL_ERROR; 952 } 953 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR; 954 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable); 955 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 956 return TCL_OK; 957 } 958 959 /* 960 ** Usage: 961 ** 962 ** sqlite3_config_heap NBYTE NMINALLOC 963 */ 964 static int test_config_heap( 965 void * clientData, 966 Tcl_Interp *interp, 967 int objc, 968 Tcl_Obj *CONST objv[] 969 ){ 970 static char *zBuf; /* Use this memory */ 971 static int szBuf; /* Bytes allocated for zBuf */ 972 int nByte; /* Size of buffer to pass to sqlite3_config() */ 973 int nMinAlloc; /* Size of minimum allocation */ 974 int rc; /* Return code of sqlite3_config() */ 975 976 Tcl_Obj * CONST *aArg = &objv[1]; 977 int nArg = objc-1; 978 979 if( nArg!=2 ){ 980 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC"); 981 return TCL_ERROR; 982 } 983 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR; 984 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR; 985 986 if( nByte==0 ){ 987 free( zBuf ); 988 zBuf = 0; 989 szBuf = 0; 990 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); 991 }else{ 992 zBuf = realloc(zBuf, nByte); 993 szBuf = nByte; 994 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); 995 } 996 997 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 998 return TCL_OK; 999 } 1000 1001 /* 1002 ** Usage: 1003 ** 1004 ** sqlite3_dump_memsys3 FILENAME 1005 ** sqlite3_dump_memsys5 FILENAME 1006 ** 1007 ** Write a summary of unfreed memsys3 allocations to FILENAME. 1008 */ 1009 static int test_dump_memsys3( 1010 void * clientData, 1011 Tcl_Interp *interp, 1012 int objc, 1013 Tcl_Obj *CONST objv[] 1014 ){ 1015 if( objc!=2 ){ 1016 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 1017 return TCL_ERROR; 1018 } 1019 1020 switch( (int)clientData ){ 1021 case 3: { 1022 #ifdef SQLITE_ENABLE_MEMSYS3 1023 extern void sqlite3Memsys3Dump(const char*); 1024 sqlite3Memsys3Dump(Tcl_GetString(objv[1])); 1025 break; 1026 #endif 1027 } 1028 case 5: { 1029 #ifdef SQLITE_ENABLE_MEMSYS5 1030 extern void sqlite3Memsys5Dump(const char*); 1031 sqlite3Memsys5Dump(Tcl_GetString(objv[1])); 1032 break; 1033 #endif 1034 } 1035 } 1036 return TCL_OK; 1037 } 1038 1039 /* 1040 ** Usage: sqlite3_status OPCODE RESETFLAG 1041 ** 1042 ** Return a list of three elements which are the sqlite3_status() return 1043 ** code, the current value, and the high-water mark value. 1044 */ 1045 static int test_status( 1046 void * clientData, 1047 Tcl_Interp *interp, 1048 int objc, 1049 Tcl_Obj *CONST objv[] 1050 ){ 1051 int rc, iValue, mxValue; 1052 int i, op, resetFlag; 1053 const char *zOpName; 1054 static const struct { 1055 const char *zName; 1056 int op; 1057 } aOp[] = { 1058 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, 1059 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, 1060 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, 1061 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, 1062 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, 1063 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, 1064 }; 1065 Tcl_Obj *pResult; 1066 if( objc!=3 ){ 1067 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1068 return TCL_ERROR; 1069 } 1070 zOpName = Tcl_GetString(objv[1]); 1071 for(i=0; i<ArraySize(aOp); i++){ 1072 if( strcmp(aOp[i].zName, zOpName)==0 ){ 1073 op = aOp[i].op; 1074 break; 1075 } 1076 } 1077 if( i>=ArraySize(aOp) ){ 1078 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; 1079 } 1080 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; 1081 iValue = 0; 1082 mxValue = 0; 1083 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); 1084 pResult = Tcl_NewObj(); 1085 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1086 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1087 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1088 Tcl_SetObjResult(interp, pResult); 1089 return TCL_OK; 1090 } 1091 1092 /* 1093 ** install_malloc_faultsim BOOLEAN 1094 */ 1095 static int test_install_malloc_faultsim( 1096 void * clientData, 1097 Tcl_Interp *interp, 1098 int objc, 1099 Tcl_Obj *CONST objv[] 1100 ){ 1101 int rc; 1102 int isInstall; 1103 1104 if( objc!=2 ){ 1105 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 1106 return TCL_ERROR; 1107 } 1108 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 1109 return TCL_ERROR; 1110 } 1111 rc = faultsimInstall(isInstall); 1112 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1113 return TCL_OK; 1114 } 1115 1116 /* 1117 ** Register commands with the TCL interpreter. 1118 */ 1119 int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 1120 static struct { 1121 char *zName; 1122 Tcl_ObjCmdProc *xProc; 1123 int clientData; 1124 } aObjCmd[] = { 1125 { "sqlite3_malloc", test_malloc ,0 }, 1126 { "sqlite3_realloc", test_realloc ,0 }, 1127 { "sqlite3_free", test_free ,0 }, 1128 { "memset", test_memset ,0 }, 1129 { "memget", test_memget ,0 }, 1130 { "sqlite3_memory_used", test_memory_used ,0 }, 1131 { "sqlite3_memory_highwater", test_memory_highwater ,0 }, 1132 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 }, 1133 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 }, 1134 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 }, 1135 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 }, 1136 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 }, 1137 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 }, 1138 { "sqlite3_memdebug_log", test_memdebug_log ,0 }, 1139 { "sqlite3_config_scratch", test_config_scratch ,0 }, 1140 { "sqlite3_config_pagecache", test_config_pagecache ,0 }, 1141 { "sqlite3_status", test_status ,0 }, 1142 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 }, 1143 { "sqlite3_config_heap", test_config_heap ,0 }, 1144 { "sqlite3_config_memstatus", test_config_memstatus ,0 }, 1145 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, 1146 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 } 1147 }; 1148 int i; 1149 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 1150 ClientData c = (ClientData)aObjCmd[i].clientData; 1151 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); 1152 } 1153 return TCL_OK; 1154 } 1155 #endif 1156