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.43 2008/07/29 14:29:07 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 = 0; 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 free(buf); 885 if( sz<0 ){ 886 buf = 0; 887 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); 888 }else{ 889 buf = malloc( (sz+4)*N ); 890 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); 891 } 892 pResult = Tcl_NewObj(); 893 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 894 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 895 Tcl_SetObjResult(interp, pResult); 896 return TCL_OK; 897 } 898 899 /* 900 ** Usage: sqlite3_config_pagecache SIZE N 901 ** 902 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. 903 ** The buffer is static and is of limited size. N might be 904 ** adjusted downward as needed to accomodate the requested size. 905 ** The revised value of N is returned. 906 ** 907 ** A negative SIZE causes the buffer pointer to be NULL. 908 */ 909 static int test_config_pagecache( 910 void * clientData, 911 Tcl_Interp *interp, 912 int objc, 913 Tcl_Obj *CONST objv[] 914 ){ 915 int sz, N, rc; 916 Tcl_Obj *pResult; 917 static char *buf = 0; 918 if( objc!=3 ){ 919 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 920 return TCL_ERROR; 921 } 922 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 923 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 924 free(buf); 925 if( sz<0 ){ 926 buf = 0; 927 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); 928 }else{ 929 buf = malloc( (sz+4)*N ); 930 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); 931 } 932 pResult = Tcl_NewObj(); 933 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 934 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 935 Tcl_SetObjResult(interp, pResult); 936 return TCL_OK; 937 } 938 939 /* 940 ** Usage: sqlite3_config_memstatus BOOLEAN 941 ** 942 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. 943 */ 944 static int test_config_memstatus( 945 void * clientData, 946 Tcl_Interp *interp, 947 int objc, 948 Tcl_Obj *CONST objv[] 949 ){ 950 int enable, rc; 951 if( objc!=2 ){ 952 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 953 return TCL_ERROR; 954 } 955 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR; 956 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable); 957 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 958 return TCL_OK; 959 } 960 961 /* 962 ** Usage: sqlite3_config_chunkalloc 963 ** 964 */ 965 static int test_config_chunkalloc( 966 void * clientData, 967 Tcl_Interp *interp, 968 int objc, 969 Tcl_Obj *CONST objv[] 970 ){ 971 int rc; 972 int nThreshold; 973 if( objc!=2 ){ 974 Tcl_WrongNumArgs(interp, 1, objv, "THRESHOLD"); 975 return TCL_ERROR; 976 } 977 if( Tcl_GetIntFromObj(interp, objv[1], &nThreshold) ) return TCL_ERROR; 978 rc = sqlite3_config(SQLITE_CONFIG_CHUNKALLOC, nThreshold); 979 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 980 return TCL_OK; 981 } 982 983 /* 984 ** Usage: sqlite3_config_lookaside SIZE COUNT 985 ** 986 */ 987 static int test_config_lookaside( 988 void * clientData, 989 Tcl_Interp *interp, 990 int objc, 991 Tcl_Obj *CONST objv[] 992 ){ 993 int rc; 994 int sz, cnt; 995 if( objc!=3 ){ 996 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT"); 997 return TCL_ERROR; 998 } 999 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 1000 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR; 1001 rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt); 1002 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 1003 return TCL_OK; 1004 } 1005 1006 1007 /* 1008 ** Usage: sqlite3_db_config_lookaside CONNECTION SIZE COUNT 1009 ** 1010 */ 1011 static int test_db_config_lookaside( 1012 void * clientData, 1013 Tcl_Interp *interp, 1014 int objc, 1015 Tcl_Obj *CONST objv[] 1016 ){ 1017 int rc; 1018 int sz, cnt; 1019 sqlite3 *db; 1020 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1021 if( objc!=4 ){ 1022 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT"); 1023 return TCL_ERROR; 1024 } 1025 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1026 if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR; 1027 if( Tcl_GetIntFromObj(interp, objv[3], &cnt) ) return TCL_ERROR; 1028 rc = sqlite3_db_config(db, SQLITE_CONFIG_LOOKASIDE, sz, cnt); 1029 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 1030 return TCL_OK; 1031 } 1032 1033 /* 1034 ** Usage: 1035 ** 1036 ** sqlite3_config_heap NBYTE NMINALLOC 1037 */ 1038 static int test_config_heap( 1039 void * clientData, 1040 Tcl_Interp *interp, 1041 int objc, 1042 Tcl_Obj *CONST objv[] 1043 ){ 1044 static char *zBuf; /* Use this memory */ 1045 static int szBuf; /* Bytes allocated for zBuf */ 1046 int nByte; /* Size of buffer to pass to sqlite3_config() */ 1047 int nMinAlloc; /* Size of minimum allocation */ 1048 int rc; /* Return code of sqlite3_config() */ 1049 1050 Tcl_Obj * CONST *aArg = &objv[1]; 1051 int nArg = objc-1; 1052 1053 if( nArg!=2 ){ 1054 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC"); 1055 return TCL_ERROR; 1056 } 1057 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR; 1058 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR; 1059 1060 if( nByte==0 ){ 1061 free( zBuf ); 1062 zBuf = 0; 1063 szBuf = 0; 1064 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); 1065 }else{ 1066 zBuf = realloc(zBuf, nByte); 1067 szBuf = nByte; 1068 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); 1069 } 1070 1071 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1072 return TCL_OK; 1073 } 1074 1075 /* 1076 ** Usage: 1077 ** 1078 ** sqlite3_dump_memsys3 FILENAME 1079 ** sqlite3_dump_memsys5 FILENAME 1080 ** 1081 ** Write a summary of unfreed memsys3 allocations to FILENAME. 1082 */ 1083 static int test_dump_memsys3( 1084 void * clientData, 1085 Tcl_Interp *interp, 1086 int objc, 1087 Tcl_Obj *CONST objv[] 1088 ){ 1089 if( objc!=2 ){ 1090 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 1091 return TCL_ERROR; 1092 } 1093 1094 switch( (int)clientData ){ 1095 case 3: { 1096 #ifdef SQLITE_ENABLE_MEMSYS3 1097 extern void sqlite3Memsys3Dump(const char*); 1098 sqlite3Memsys3Dump(Tcl_GetString(objv[1])); 1099 break; 1100 #endif 1101 } 1102 case 5: { 1103 #ifdef SQLITE_ENABLE_MEMSYS5 1104 extern void sqlite3Memsys5Dump(const char*); 1105 sqlite3Memsys5Dump(Tcl_GetString(objv[1])); 1106 break; 1107 #endif 1108 } 1109 } 1110 return TCL_OK; 1111 } 1112 1113 /* 1114 ** Usage: sqlite3_status OPCODE RESETFLAG 1115 ** 1116 ** Return a list of three elements which are the sqlite3_status() return 1117 ** code, the current value, and the high-water mark value. 1118 */ 1119 static int test_status( 1120 void * clientData, 1121 Tcl_Interp *interp, 1122 int objc, 1123 Tcl_Obj *CONST objv[] 1124 ){ 1125 int rc, iValue, mxValue; 1126 int i, op, resetFlag; 1127 const char *zOpName; 1128 static const struct { 1129 const char *zName; 1130 int op; 1131 } aOp[] = { 1132 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, 1133 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, 1134 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, 1135 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, 1136 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, 1137 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, 1138 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK }, 1139 }; 1140 Tcl_Obj *pResult; 1141 if( objc!=3 ){ 1142 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1143 return TCL_ERROR; 1144 } 1145 zOpName = Tcl_GetString(objv[1]); 1146 for(i=0; i<ArraySize(aOp); i++){ 1147 if( strcmp(aOp[i].zName, zOpName)==0 ){ 1148 op = aOp[i].op; 1149 break; 1150 } 1151 } 1152 if( i>=ArraySize(aOp) ){ 1153 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; 1154 } 1155 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; 1156 iValue = 0; 1157 mxValue = 0; 1158 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); 1159 pResult = Tcl_NewObj(); 1160 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1161 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1162 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1163 Tcl_SetObjResult(interp, pResult); 1164 return TCL_OK; 1165 } 1166 1167 /* 1168 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG 1169 ** 1170 ** Return a list of three elements which are the sqlite3_db_status() return 1171 ** code, the current value, and the high-water mark value. 1172 */ 1173 static int test_db_status( 1174 void * clientData, 1175 Tcl_Interp *interp, 1176 int objc, 1177 Tcl_Obj *CONST objv[] 1178 ){ 1179 int rc, iValue, mxValue; 1180 int i, op, resetFlag; 1181 const char *zOpName; 1182 sqlite3 *db; 1183 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1184 static const struct { 1185 const char *zName; 1186 int op; 1187 } aOp[] = { 1188 { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, 1189 }; 1190 Tcl_Obj *pResult; 1191 if( objc!=4 ){ 1192 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1193 return TCL_ERROR; 1194 } 1195 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1196 zOpName = Tcl_GetString(objv[2]); 1197 for(i=0; i<ArraySize(aOp); i++){ 1198 if( strcmp(aOp[i].zName, zOpName)==0 ){ 1199 op = aOp[i].op; 1200 break; 1201 } 1202 } 1203 if( i>=ArraySize(aOp) ){ 1204 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR; 1205 } 1206 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR; 1207 iValue = 0; 1208 mxValue = 0; 1209 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag); 1210 pResult = Tcl_NewObj(); 1211 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1212 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1213 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1214 Tcl_SetObjResult(interp, pResult); 1215 return TCL_OK; 1216 } 1217 1218 /* 1219 ** install_malloc_faultsim BOOLEAN 1220 */ 1221 static int test_install_malloc_faultsim( 1222 void * clientData, 1223 Tcl_Interp *interp, 1224 int objc, 1225 Tcl_Obj *CONST objv[] 1226 ){ 1227 int rc; 1228 int isInstall; 1229 1230 if( objc!=2 ){ 1231 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 1232 return TCL_ERROR; 1233 } 1234 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 1235 return TCL_ERROR; 1236 } 1237 rc = faultsimInstall(isInstall); 1238 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1239 return TCL_OK; 1240 } 1241 1242 /* 1243 ** Register commands with the TCL interpreter. 1244 */ 1245 int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 1246 static struct { 1247 char *zName; 1248 Tcl_ObjCmdProc *xProc; 1249 int clientData; 1250 } aObjCmd[] = { 1251 { "sqlite3_malloc", test_malloc ,0 }, 1252 { "sqlite3_realloc", test_realloc ,0 }, 1253 { "sqlite3_free", test_free ,0 }, 1254 { "memset", test_memset ,0 }, 1255 { "memget", test_memget ,0 }, 1256 { "sqlite3_memory_used", test_memory_used ,0 }, 1257 { "sqlite3_memory_highwater", test_memory_highwater ,0 }, 1258 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 }, 1259 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 }, 1260 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 }, 1261 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 }, 1262 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 }, 1263 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 }, 1264 { "sqlite3_memdebug_log", test_memdebug_log ,0 }, 1265 { "sqlite3_config_scratch", test_config_scratch ,0 }, 1266 { "sqlite3_config_pagecache", test_config_pagecache ,0 }, 1267 { "sqlite3_status", test_status ,0 }, 1268 { "sqlite3_db_status", test_db_status ,0 }, 1269 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 }, 1270 { "sqlite3_config_heap", test_config_heap ,0 }, 1271 { "sqlite3_config_memstatus", test_config_memstatus ,0 }, 1272 { "sqlite3_config_chunkalloc", test_config_chunkalloc ,0 }, 1273 { "sqlite3_config_lookaside", test_config_lookaside ,0 }, 1274 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, 1275 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, 1276 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 } 1277 }; 1278 int i; 1279 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 1280 ClientData c = (ClientData)aObjCmd[i].clientData; 1281 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); 1282 } 1283 return TCL_OK; 1284 } 1285 #endif 1286