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.51 2008/11/19 01:20:26 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 sqlite3_mem_methods m; 208 assert(memfault.m.xMalloc); 209 210 /* One should be able to reset the default memory allocator by storing 211 ** a zeroed allocator then calling GETMALLOC. */ 212 memset(&m, 0, sizeof(m)); 213 sqlite3_config(SQLITE_CONFIG_MALLOC, &m); 214 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m); 215 assert( memcmp(&m, &memfault.m, sizeof(m))==0 ); 216 217 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m); 218 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0); 219 } 220 221 if( rc==SQLITE_OK ){ 222 memfault.isInstalled = 1; 223 } 224 return rc; 225 } 226 227 #ifdef SQLITE_TEST 228 229 /* 230 ** This function is implemented in test1.c. Returns a pointer to a static 231 ** buffer containing the symbolic SQLite error code that corresponds to 232 ** the least-significant 8-bits of the integer passed as an argument. 233 ** For example: 234 ** 235 ** sqlite3TestErrorName(1) -> "SQLITE_ERROR" 236 */ 237 const char *sqlite3TestErrorName(int); 238 239 /* 240 ** Transform pointers to text and back again 241 */ 242 static void pointerToText(void *p, char *z){ 243 static const char zHex[] = "0123456789abcdef"; 244 int i, k; 245 unsigned int u; 246 sqlite3_uint64 n; 247 if( p==0 ){ 248 strcpy(z, "0"); 249 return; 250 } 251 if( sizeof(n)==sizeof(p) ){ 252 memcpy(&n, &p, sizeof(p)); 253 }else if( sizeof(u)==sizeof(p) ){ 254 memcpy(&u, &p, sizeof(u)); 255 n = u; 256 }else{ 257 assert( 0 ); 258 } 259 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){ 260 z[k] = zHex[n&0xf]; 261 n >>= 4; 262 } 263 z[sizeof(p)*2] = 0; 264 } 265 static int hexToInt(int h){ 266 if( h>='0' && h<='9' ){ 267 return h - '0'; 268 }else if( h>='a' && h<='f' ){ 269 return h - 'a' + 10; 270 }else{ 271 return -1; 272 } 273 } 274 static int textToPointer(const char *z, void **pp){ 275 sqlite3_uint64 n = 0; 276 int i; 277 unsigned int u; 278 for(i=0; i<sizeof(void*)*2 && z[0]; i++){ 279 int v; 280 v = hexToInt(*z++); 281 if( v<0 ) return TCL_ERROR; 282 n = n*16 + v; 283 } 284 if( *z!=0 ) return TCL_ERROR; 285 if( sizeof(n)==sizeof(*pp) ){ 286 memcpy(pp, &n, sizeof(n)); 287 }else if( sizeof(u)==sizeof(*pp) ){ 288 u = (unsigned int)n; 289 memcpy(pp, &u, sizeof(u)); 290 }else{ 291 assert( 0 ); 292 } 293 return TCL_OK; 294 } 295 296 /* 297 ** Usage: sqlite3_malloc NBYTES 298 ** 299 ** Raw test interface for sqlite3_malloc(). 300 */ 301 static int test_malloc( 302 void * clientData, 303 Tcl_Interp *interp, 304 int objc, 305 Tcl_Obj *CONST objv[] 306 ){ 307 int nByte; 308 void *p; 309 char zOut[100]; 310 if( objc!=2 ){ 311 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES"); 312 return TCL_ERROR; 313 } 314 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR; 315 p = sqlite3_malloc((unsigned)nByte); 316 pointerToText(p, zOut); 317 Tcl_AppendResult(interp, zOut, NULL); 318 return TCL_OK; 319 } 320 321 /* 322 ** Usage: sqlite3_realloc PRIOR NBYTES 323 ** 324 ** Raw test interface for sqlite3_realloc(). 325 */ 326 static int test_realloc( 327 void * clientData, 328 Tcl_Interp *interp, 329 int objc, 330 Tcl_Obj *CONST objv[] 331 ){ 332 int nByte; 333 void *pPrior, *p; 334 char zOut[100]; 335 if( objc!=3 ){ 336 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES"); 337 return TCL_ERROR; 338 } 339 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR; 340 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 341 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 342 return TCL_ERROR; 343 } 344 p = sqlite3_realloc(pPrior, (unsigned)nByte); 345 pointerToText(p, zOut); 346 Tcl_AppendResult(interp, zOut, NULL); 347 return TCL_OK; 348 } 349 350 /* 351 ** Usage: sqlite3_free PRIOR 352 ** 353 ** Raw test interface for sqlite3_free(). 354 */ 355 static int test_free( 356 void * clientData, 357 Tcl_Interp *interp, 358 int objc, 359 Tcl_Obj *CONST objv[] 360 ){ 361 void *pPrior; 362 if( objc!=2 ){ 363 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR"); 364 return TCL_ERROR; 365 } 366 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){ 367 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 368 return TCL_ERROR; 369 } 370 sqlite3_free(pPrior); 371 return TCL_OK; 372 } 373 374 /* 375 ** These routines are in test_hexio.c 376 */ 377 int sqlite3TestHexToBin(const char *, int, char *); 378 int sqlite3TestBinToHex(char*,int); 379 380 /* 381 ** Usage: memset ADDRESS SIZE HEX 382 ** 383 ** Set a chunk of memory (obtained from malloc, probably) to a 384 ** specified hex pattern. 385 */ 386 static int test_memset( 387 void * clientData, 388 Tcl_Interp *interp, 389 int objc, 390 Tcl_Obj *CONST objv[] 391 ){ 392 void *p; 393 int size, n, i; 394 char *zHex; 395 char *zOut; 396 char zBin[100]; 397 398 if( objc!=4 ){ 399 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX"); 400 return TCL_ERROR; 401 } 402 if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 403 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 404 return TCL_ERROR; 405 } 406 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 407 return TCL_ERROR; 408 } 409 if( size<=0 ){ 410 Tcl_AppendResult(interp, "size must be positive", (char*)0); 411 return TCL_ERROR; 412 } 413 zHex = Tcl_GetStringFromObj(objv[3], &n); 414 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2; 415 n = sqlite3TestHexToBin(zHex, n, zBin); 416 if( n==0 ){ 417 Tcl_AppendResult(interp, "no data", (char*)0); 418 return TCL_ERROR; 419 } 420 zOut = p; 421 for(i=0; i<size; i++){ 422 zOut[i] = zBin[i%n]; 423 } 424 return TCL_OK; 425 } 426 427 /* 428 ** Usage: memget ADDRESS SIZE 429 ** 430 ** Return memory as hexadecimal text. 431 */ 432 static int test_memget( 433 void * clientData, 434 Tcl_Interp *interp, 435 int objc, 436 Tcl_Obj *CONST objv[] 437 ){ 438 void *p; 439 int size, n; 440 char *zBin; 441 char zHex[100]; 442 443 if( objc!=3 ){ 444 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE"); 445 return TCL_ERROR; 446 } 447 if( textToPointer(Tcl_GetString(objv[1]), &p) ){ 448 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0); 449 return TCL_ERROR; 450 } 451 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){ 452 return TCL_ERROR; 453 } 454 if( size<=0 ){ 455 Tcl_AppendResult(interp, "size must be positive", (char*)0); 456 return TCL_ERROR; 457 } 458 zBin = p; 459 while( size>0 ){ 460 if( size>(sizeof(zHex)-1)/2 ){ 461 n = (sizeof(zHex)-1)/2; 462 }else{ 463 n = size; 464 } 465 memcpy(zHex, zBin, n); 466 zBin += n; 467 size -= n; 468 sqlite3TestBinToHex(zHex, n); 469 Tcl_AppendResult(interp, zHex, (char*)0); 470 } 471 return TCL_OK; 472 } 473 474 /* 475 ** Usage: sqlite3_memory_used 476 ** 477 ** Raw test interface for sqlite3_memory_used(). 478 */ 479 static int test_memory_used( 480 void * clientData, 481 Tcl_Interp *interp, 482 int objc, 483 Tcl_Obj *CONST objv[] 484 ){ 485 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); 486 return TCL_OK; 487 } 488 489 /* 490 ** Usage: sqlite3_memory_highwater ?RESETFLAG? 491 ** 492 ** Raw test interface for sqlite3_memory_highwater(). 493 */ 494 static int test_memory_highwater( 495 void * clientData, 496 Tcl_Interp *interp, 497 int objc, 498 Tcl_Obj *CONST objv[] 499 ){ 500 int resetFlag = 0; 501 if( objc!=1 && objc!=2 ){ 502 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?"); 503 return TCL_ERROR; 504 } 505 if( objc==2 ){ 506 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR; 507 } 508 Tcl_SetObjResult(interp, 509 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag))); 510 return TCL_OK; 511 } 512 513 /* 514 ** Usage: sqlite3_memdebug_backtrace DEPTH 515 ** 516 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined 517 ** then this routine is a no-op. 518 */ 519 static int test_memdebug_backtrace( 520 void * clientData, 521 Tcl_Interp *interp, 522 int objc, 523 Tcl_Obj *CONST objv[] 524 ){ 525 int depth; 526 if( objc!=2 ){ 527 Tcl_WrongNumArgs(interp, 1, objv, "DEPT"); 528 return TCL_ERROR; 529 } 530 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR; 531 #ifdef SQLITE_MEMDEBUG 532 { 533 extern void sqlite3MemdebugBacktrace(int); 534 sqlite3MemdebugBacktrace(depth); 535 } 536 #endif 537 return TCL_OK; 538 } 539 540 /* 541 ** Usage: sqlite3_memdebug_dump FILENAME 542 ** 543 ** Write a summary of unfreed memory to FILENAME. 544 */ 545 static int test_memdebug_dump( 546 void * clientData, 547 Tcl_Interp *interp, 548 int objc, 549 Tcl_Obj *CONST objv[] 550 ){ 551 if( objc!=2 ){ 552 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 553 return TCL_ERROR; 554 } 555 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \ 556 || defined(SQLITE_POW2_MEMORY_SIZE) 557 { 558 extern void sqlite3MemdebugDump(const char*); 559 sqlite3MemdebugDump(Tcl_GetString(objv[1])); 560 } 561 #endif 562 return TCL_OK; 563 } 564 565 /* 566 ** Usage: sqlite3_memdebug_malloc_count 567 ** 568 ** Return the total number of times malloc() has been called. 569 */ 570 static int test_memdebug_malloc_count( 571 void * clientData, 572 Tcl_Interp *interp, 573 int objc, 574 Tcl_Obj *CONST objv[] 575 ){ 576 int nMalloc = -1; 577 if( objc!=1 ){ 578 Tcl_WrongNumArgs(interp, 1, objv, ""); 579 return TCL_ERROR; 580 } 581 #if defined(SQLITE_MEMDEBUG) 582 { 583 extern int sqlite3MemdebugMallocCount(); 584 nMalloc = sqlite3MemdebugMallocCount(); 585 } 586 #endif 587 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); 588 return TCL_OK; 589 } 590 591 592 /* 593 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? 594 ** 595 ** where options are: 596 ** 597 ** -repeat <count> 598 ** -benigncnt <varname> 599 ** 600 ** Arrange for a simulated malloc() failure after COUNTER successes. 601 ** If a repeat count is specified, the fault is repeated that many 602 ** times. 603 ** 604 ** Each call to this routine overrides the prior counter value. 605 ** This routine returns the number of simulated failures that have 606 ** happened since the previous call to this routine. 607 ** 608 ** To disable simulated failures, use a COUNTER of -1. 609 */ 610 static int test_memdebug_fail( 611 void * clientData, 612 Tcl_Interp *interp, 613 int objc, 614 Tcl_Obj *CONST objv[] 615 ){ 616 int ii; 617 int iFail; 618 int nRepeat = 1; 619 Tcl_Obj *pBenignCnt = 0; 620 int nBenign; 621 int nFail = 0; 622 623 if( objc<2 ){ 624 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?"); 625 return TCL_ERROR; 626 } 627 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; 628 629 for(ii=2; ii<objc; ii+=2){ 630 int nOption; 631 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption); 632 char *zErr = 0; 633 634 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){ 635 if( ii==(objc-1) ){ 636 zErr = "option requires an argument: "; 637 }else{ 638 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ 639 return TCL_ERROR; 640 } 641 } 642 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){ 643 if( ii==(objc-1) ){ 644 zErr = "option requires an argument: "; 645 }else{ 646 pBenignCnt = objv[ii+1]; 647 } 648 }else{ 649 zErr = "unknown option: "; 650 } 651 652 if( zErr ){ 653 Tcl_AppendResult(interp, zErr, zOption, 0); 654 return TCL_ERROR; 655 } 656 } 657 658 nBenign = faultsimBenignFailures(); 659 nFail = faultsimFailures(); 660 faultsimConfig(iFail, nRepeat); 661 662 if( pBenignCnt ){ 663 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); 664 } 665 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); 666 return TCL_OK; 667 } 668 669 /* 670 ** Usage: sqlite3_memdebug_pending 671 ** 672 ** Return the number of malloc() calls that will succeed before a 673 ** simulated failure occurs. A negative return value indicates that 674 ** no malloc() failure is scheduled. 675 */ 676 static int test_memdebug_pending( 677 void * clientData, 678 Tcl_Interp *interp, 679 int objc, 680 Tcl_Obj *CONST objv[] 681 ){ 682 int nPending; 683 if( objc!=1 ){ 684 Tcl_WrongNumArgs(interp, 1, objv, ""); 685 return TCL_ERROR; 686 } 687 nPending = faultsimPending(); 688 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending)); 689 return TCL_OK; 690 } 691 692 693 /* 694 ** Usage: sqlite3_memdebug_settitle TITLE 695 ** 696 ** Set a title string stored with each allocation. The TITLE is 697 ** typically the name of the test that was running when the 698 ** allocation occurred. The TITLE is stored with the allocation 699 ** and can be used to figure out which tests are leaking memory. 700 ** 701 ** Each title overwrite the previous. 702 */ 703 static int test_memdebug_settitle( 704 void * clientData, 705 Tcl_Interp *interp, 706 int objc, 707 Tcl_Obj *CONST objv[] 708 ){ 709 const char *zTitle; 710 if( objc!=2 ){ 711 Tcl_WrongNumArgs(interp, 1, objv, "TITLE"); 712 return TCL_ERROR; 713 } 714 zTitle = Tcl_GetString(objv[1]); 715 #ifdef SQLITE_MEMDEBUG 716 { 717 extern int sqlite3MemdebugSettitle(const char*); 718 sqlite3MemdebugSettitle(zTitle); 719 } 720 #endif 721 return TCL_OK; 722 } 723 724 #define MALLOC_LOG_FRAMES 10 725 static Tcl_HashTable aMallocLog; 726 static int mallocLogEnabled = 0; 727 728 typedef struct MallocLog MallocLog; 729 struct MallocLog { 730 int nCall; 731 int nByte; 732 }; 733 734 #ifdef SQLITE_MEMDEBUG 735 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){ 736 if( mallocLogEnabled ){ 737 MallocLog *pLog; 738 Tcl_HashEntry *pEntry; 739 int isNew; 740 741 int aKey[MALLOC_LOG_FRAMES]; 742 int nKey = sizeof(int)*MALLOC_LOG_FRAMES; 743 744 memset(aKey, 0, nKey); 745 if( (sizeof(void*)*nFrame)<nKey ){ 746 nKey = nFrame*sizeof(void*); 747 } 748 memcpy(aKey, aFrame, nKey); 749 750 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew); 751 if( isNew ){ 752 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog)); 753 memset(pLog, 0, sizeof(MallocLog)); 754 Tcl_SetHashValue(pEntry, (ClientData)pLog); 755 }else{ 756 pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 757 } 758 759 pLog->nCall++; 760 pLog->nByte += nByte; 761 } 762 } 763 #endif /* SQLITE_MEMDEBUG */ 764 765 static void test_memdebug_log_clear(){ 766 Tcl_HashSearch search; 767 Tcl_HashEntry *pEntry; 768 for( 769 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 770 pEntry; 771 pEntry=Tcl_NextHashEntry(&search) 772 ){ 773 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 774 Tcl_Free((char *)pLog); 775 } 776 Tcl_DeleteHashTable(&aMallocLog); 777 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 778 } 779 780 static int test_memdebug_log( 781 void * clientData, 782 Tcl_Interp *interp, 783 int objc, 784 Tcl_Obj *CONST objv[] 785 ){ 786 static int isInit = 0; 787 int iSub; 788 789 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" }; 790 enum MB_enum { 791 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC 792 }; 793 794 if( !isInit ){ 795 #ifdef SQLITE_MEMDEBUG 796 extern void sqlite3MemdebugBacktraceCallback( 797 void (*xBacktrace)(int, int, void **)); 798 sqlite3MemdebugBacktraceCallback(test_memdebug_callback); 799 #endif 800 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES); 801 isInit = 1; 802 } 803 804 if( objc<2 ){ 805 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 806 } 807 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){ 808 return TCL_ERROR; 809 } 810 811 switch( (enum MB_enum)iSub ){ 812 case MB_LOG_START: 813 mallocLogEnabled = 1; 814 break; 815 case MB_LOG_STOP: 816 mallocLogEnabled = 0; 817 break; 818 case MB_LOG_DUMP: { 819 Tcl_HashSearch search; 820 Tcl_HashEntry *pEntry; 821 Tcl_Obj *pRet = Tcl_NewObj(); 822 823 assert(sizeof(int)==sizeof(void*)); 824 825 for( 826 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search); 827 pEntry; 828 pEntry=Tcl_NextHashEntry(&search) 829 ){ 830 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2]; 831 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); 832 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry); 833 int ii; 834 835 apElem[0] = Tcl_NewIntObj(pLog->nCall); 836 apElem[1] = Tcl_NewIntObj(pLog->nByte); 837 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){ 838 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]); 839 } 840 841 Tcl_ListObjAppendElement(interp, pRet, 842 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem) 843 ); 844 } 845 846 Tcl_SetObjResult(interp, pRet); 847 break; 848 } 849 case MB_LOG_CLEAR: { 850 test_memdebug_log_clear(); 851 break; 852 } 853 854 case MB_LOG_SYNC: { 855 #ifdef SQLITE_MEMDEBUG 856 extern void sqlite3MemdebugSync(); 857 test_memdebug_log_clear(); 858 mallocLogEnabled = 1; 859 sqlite3MemdebugSync(); 860 #endif 861 break; 862 } 863 } 864 865 return TCL_OK; 866 } 867 868 /* 869 ** Usage: sqlite3_config_scratch SIZE N 870 ** 871 ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. 872 ** The buffer is static and is of limited size. N might be 873 ** adjusted downward as needed to accomodate the requested size. 874 ** The revised value of N is returned. 875 ** 876 ** A negative SIZE causes the buffer pointer to be NULL. 877 */ 878 static int test_config_scratch( 879 void * clientData, 880 Tcl_Interp *interp, 881 int objc, 882 Tcl_Obj *CONST objv[] 883 ){ 884 int sz, N, rc; 885 Tcl_Obj *pResult; 886 static char *buf = 0; 887 if( objc!=3 ){ 888 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 889 return TCL_ERROR; 890 } 891 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 892 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 893 free(buf); 894 if( sz<0 ){ 895 buf = 0; 896 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0); 897 }else{ 898 buf = malloc( sz*N + 1 ); 899 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N); 900 } 901 pResult = Tcl_NewObj(); 902 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 903 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 904 Tcl_SetObjResult(interp, pResult); 905 return TCL_OK; 906 } 907 908 /* 909 ** Usage: sqlite3_config_pagecache SIZE N 910 ** 911 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. 912 ** The buffer is static and is of limited size. N might be 913 ** adjusted downward as needed to accomodate the requested size. 914 ** The revised value of N is returned. 915 ** 916 ** A negative SIZE causes the buffer pointer to be NULL. 917 */ 918 static int test_config_pagecache( 919 void * clientData, 920 Tcl_Interp *interp, 921 int objc, 922 Tcl_Obj *CONST objv[] 923 ){ 924 int sz, N, rc; 925 Tcl_Obj *pResult; 926 static char *buf = 0; 927 if( objc!=3 ){ 928 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N"); 929 return TCL_ERROR; 930 } 931 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 932 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR; 933 free(buf); 934 if( sz<0 ){ 935 buf = 0; 936 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0); 937 }else{ 938 buf = malloc( sz*N ); 939 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N); 940 } 941 pResult = Tcl_NewObj(); 942 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 943 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N)); 944 Tcl_SetObjResult(interp, pResult); 945 return TCL_OK; 946 } 947 948 /* 949 ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED 950 ** 951 ** Set up the alternative test page cache. Install if INSTALL_FLAG is 952 ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG 953 ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive 954 ** which determines the chance of discarding a page when unpinned. 100 955 ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator 956 ** seed. 957 */ 958 static int test_alt_pcache( 959 void * clientData, 960 Tcl_Interp *interp, 961 int objc, 962 Tcl_Obj *CONST objv[] 963 ){ 964 int installFlag; 965 int discardChance; 966 int prngSeed; 967 extern void installTestPCache(int,unsigned,unsigned); 968 if( objc!=4 ){ 969 Tcl_WrongNumArgs(interp, 1, objv, "INSTALLFLAG DISCARDCHANCE PRNGSEEED"); 970 return TCL_ERROR; 971 } 972 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR; 973 if( Tcl_GetIntFromObj(interp, objv[2], &discardChance) ) return TCL_ERROR; 974 if( Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ) return TCL_ERROR; 975 if( discardChance<0 || discardChance>100 ){ 976 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100", 977 (char*)0); 978 return TCL_ERROR; 979 } 980 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed); 981 return TCL_OK; 982 } 983 984 /* 985 ** Usage: sqlite3_config_memstatus BOOLEAN 986 ** 987 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. 988 */ 989 static int test_config_memstatus( 990 void * clientData, 991 Tcl_Interp *interp, 992 int objc, 993 Tcl_Obj *CONST objv[] 994 ){ 995 int enable, rc; 996 if( objc!=2 ){ 997 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 998 return TCL_ERROR; 999 } 1000 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR; 1001 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable); 1002 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 1003 return TCL_OK; 1004 } 1005 1006 /* 1007 ** Usage: sqlite3_config_lookaside SIZE COUNT 1008 ** 1009 */ 1010 static int test_config_lookaside( 1011 void * clientData, 1012 Tcl_Interp *interp, 1013 int objc, 1014 Tcl_Obj *CONST objv[] 1015 ){ 1016 int rc; 1017 int sz, cnt; 1018 Tcl_Obj *pRet; 1019 if( objc!=3 ){ 1020 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT"); 1021 return TCL_ERROR; 1022 } 1023 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR; 1024 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR; 1025 pRet = Tcl_NewObj(); 1026 Tcl_ListObjAppendElement( 1027 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside) 1028 ); 1029 Tcl_ListObjAppendElement( 1030 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside) 1031 ); 1032 rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt); 1033 Tcl_SetObjResult(interp, pRet); 1034 return TCL_OK; 1035 } 1036 1037 1038 /* 1039 ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT 1040 ** 1041 ** There are two static buffers with BUFID 1 and 2. Each static buffer 1042 ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL 1043 ** which will cause sqlite3_db_config() to allocate space on its own. 1044 */ 1045 static int test_db_config_lookaside( 1046 void * clientData, 1047 Tcl_Interp *interp, 1048 int objc, 1049 Tcl_Obj *CONST objv[] 1050 ){ 1051 int rc; 1052 int sz, cnt; 1053 sqlite3 *db; 1054 int bufid; 1055 static char azBuf[2][10000]; 1056 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1057 if( objc!=5 ){ 1058 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT"); 1059 return TCL_ERROR; 1060 } 1061 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1062 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR; 1063 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR; 1064 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR; 1065 if( bufid==0 ){ 1066 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt); 1067 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){ 1068 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt); 1069 }else{ 1070 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0); 1071 return TCL_ERROR; 1072 } 1073 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 1074 return TCL_OK; 1075 } 1076 1077 /* 1078 ** Usage: 1079 ** 1080 ** sqlite3_config_heap NBYTE NMINALLOC 1081 */ 1082 static int test_config_heap( 1083 void * clientData, 1084 Tcl_Interp *interp, 1085 int objc, 1086 Tcl_Obj *CONST objv[] 1087 ){ 1088 static char *zBuf; /* Use this memory */ 1089 static int szBuf; /* Bytes allocated for zBuf */ 1090 int nByte; /* Size of buffer to pass to sqlite3_config() */ 1091 int nMinAlloc; /* Size of minimum allocation */ 1092 int rc; /* Return code of sqlite3_config() */ 1093 1094 Tcl_Obj * CONST *aArg = &objv[1]; 1095 int nArg = objc-1; 1096 1097 if( nArg!=2 ){ 1098 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC"); 1099 return TCL_ERROR; 1100 } 1101 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR; 1102 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR; 1103 1104 if( nByte==0 ){ 1105 free( zBuf ); 1106 zBuf = 0; 1107 szBuf = 0; 1108 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0); 1109 }else{ 1110 zBuf = realloc(zBuf, nByte); 1111 szBuf = nByte; 1112 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc); 1113 } 1114 1115 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1116 return TCL_OK; 1117 } 1118 1119 /* 1120 ** tclcmd: sqlite3_config_error [DB] 1121 ** 1122 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid 1123 ** opcodes and verify that they return errors. 1124 */ 1125 static int test_config_error( 1126 void * clientData, 1127 Tcl_Interp *interp, 1128 int objc, 1129 Tcl_Obj *CONST objv[] 1130 ){ 1131 sqlite3 *db; 1132 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1133 1134 if( objc!=2 && objc!=1 ){ 1135 Tcl_WrongNumArgs(interp, 1, objv, "[DB]"); 1136 return TCL_ERROR; 1137 } 1138 if( objc==2 ){ 1139 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1140 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){ 1141 Tcl_AppendResult(interp, 1142 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR", 1143 (char*)0); 1144 return TCL_ERROR; 1145 } 1146 }else{ 1147 if( sqlite3_config(99999)!=SQLITE_ERROR ){ 1148 Tcl_AppendResult(interp, 1149 "sqlite3_config(99999) does not return SQLITE_ERROR", 1150 (char*)0); 1151 return TCL_ERROR; 1152 } 1153 } 1154 return TCL_OK; 1155 } 1156 1157 /* 1158 ** Usage: 1159 ** 1160 ** sqlite3_dump_memsys3 FILENAME 1161 ** sqlite3_dump_memsys5 FILENAME 1162 ** 1163 ** Write a summary of unfreed memsys3 allocations to FILENAME. 1164 */ 1165 static int test_dump_memsys3( 1166 void * clientData, 1167 Tcl_Interp *interp, 1168 int objc, 1169 Tcl_Obj *CONST objv[] 1170 ){ 1171 if( objc!=2 ){ 1172 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); 1173 return TCL_ERROR; 1174 } 1175 1176 switch( (int)clientData ){ 1177 case 3: { 1178 #ifdef SQLITE_ENABLE_MEMSYS3 1179 extern void sqlite3Memsys3Dump(const char*); 1180 sqlite3Memsys3Dump(Tcl_GetString(objv[1])); 1181 break; 1182 #endif 1183 } 1184 case 5: { 1185 #ifdef SQLITE_ENABLE_MEMSYS5 1186 extern void sqlite3Memsys5Dump(const char*); 1187 sqlite3Memsys5Dump(Tcl_GetString(objv[1])); 1188 break; 1189 #endif 1190 } 1191 } 1192 return TCL_OK; 1193 } 1194 1195 /* 1196 ** Usage: sqlite3_status OPCODE RESETFLAG 1197 ** 1198 ** Return a list of three elements which are the sqlite3_status() return 1199 ** code, the current value, and the high-water mark value. 1200 */ 1201 static int test_status( 1202 void * clientData, 1203 Tcl_Interp *interp, 1204 int objc, 1205 Tcl_Obj *CONST objv[] 1206 ){ 1207 int rc, iValue, mxValue; 1208 int i, op, resetFlag; 1209 const char *zOpName; 1210 static const struct { 1211 const char *zName; 1212 int op; 1213 } aOp[] = { 1214 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED }, 1215 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE }, 1216 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED }, 1217 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW }, 1218 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE }, 1219 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED }, 1220 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW }, 1221 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE }, 1222 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK }, 1223 }; 1224 Tcl_Obj *pResult; 1225 if( objc!=3 ){ 1226 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1227 return TCL_ERROR; 1228 } 1229 zOpName = Tcl_GetString(objv[1]); 1230 for(i=0; i<ArraySize(aOp); i++){ 1231 if( strcmp(aOp[i].zName, zOpName)==0 ){ 1232 op = aOp[i].op; 1233 break; 1234 } 1235 } 1236 if( i>=ArraySize(aOp) ){ 1237 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR; 1238 } 1239 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR; 1240 iValue = 0; 1241 mxValue = 0; 1242 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag); 1243 pResult = Tcl_NewObj(); 1244 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1245 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1246 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1247 Tcl_SetObjResult(interp, pResult); 1248 return TCL_OK; 1249 } 1250 1251 /* 1252 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG 1253 ** 1254 ** Return a list of three elements which are the sqlite3_db_status() return 1255 ** code, the current value, and the high-water mark value. 1256 */ 1257 static int test_db_status( 1258 void * clientData, 1259 Tcl_Interp *interp, 1260 int objc, 1261 Tcl_Obj *CONST objv[] 1262 ){ 1263 int rc, iValue, mxValue; 1264 int i, op, resetFlag; 1265 const char *zOpName; 1266 sqlite3 *db; 1267 int getDbPointer(Tcl_Interp*, const char*, sqlite3**); 1268 static const struct { 1269 const char *zName; 1270 int op; 1271 } aOp[] = { 1272 { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, 1273 }; 1274 Tcl_Obj *pResult; 1275 if( objc!=4 ){ 1276 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); 1277 return TCL_ERROR; 1278 } 1279 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1280 zOpName = Tcl_GetString(objv[2]); 1281 for(i=0; i<ArraySize(aOp); i++){ 1282 if( strcmp(aOp[i].zName, zOpName)==0 ){ 1283 op = aOp[i].op; 1284 break; 1285 } 1286 } 1287 if( i>=ArraySize(aOp) ){ 1288 if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR; 1289 } 1290 if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR; 1291 iValue = 0; 1292 mxValue = 0; 1293 rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag); 1294 pResult = Tcl_NewObj(); 1295 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc)); 1296 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue)); 1297 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue)); 1298 Tcl_SetObjResult(interp, pResult); 1299 return TCL_OK; 1300 } 1301 1302 /* 1303 ** install_malloc_faultsim BOOLEAN 1304 */ 1305 static int test_install_malloc_faultsim( 1306 void * clientData, 1307 Tcl_Interp *interp, 1308 int objc, 1309 Tcl_Obj *CONST objv[] 1310 ){ 1311 int rc; 1312 int isInstall; 1313 1314 if( objc!=2 ){ 1315 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); 1316 return TCL_ERROR; 1317 } 1318 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ 1319 return TCL_ERROR; 1320 } 1321 rc = faultsimInstall(isInstall); 1322 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); 1323 return TCL_OK; 1324 } 1325 1326 /* 1327 ** Register commands with the TCL interpreter. 1328 */ 1329 int Sqlitetest_malloc_Init(Tcl_Interp *interp){ 1330 static struct { 1331 char *zName; 1332 Tcl_ObjCmdProc *xProc; 1333 int clientData; 1334 } aObjCmd[] = { 1335 { "sqlite3_malloc", test_malloc ,0 }, 1336 { "sqlite3_realloc", test_realloc ,0 }, 1337 { "sqlite3_free", test_free ,0 }, 1338 { "memset", test_memset ,0 }, 1339 { "memget", test_memget ,0 }, 1340 { "sqlite3_memory_used", test_memory_used ,0 }, 1341 { "sqlite3_memory_highwater", test_memory_highwater ,0 }, 1342 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 }, 1343 { "sqlite3_memdebug_dump", test_memdebug_dump ,0 }, 1344 { "sqlite3_memdebug_fail", test_memdebug_fail ,0 }, 1345 { "sqlite3_memdebug_pending", test_memdebug_pending ,0 }, 1346 { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 }, 1347 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 }, 1348 { "sqlite3_memdebug_log", test_memdebug_log ,0 }, 1349 { "sqlite3_config_scratch", test_config_scratch ,0 }, 1350 { "sqlite3_config_pagecache", test_config_pagecache ,0 }, 1351 { "sqlite3_config_alt_pcache", test_alt_pcache ,0 }, 1352 { "sqlite3_status", test_status ,0 }, 1353 { "sqlite3_db_status", test_db_status ,0 }, 1354 { "install_malloc_faultsim", test_install_malloc_faultsim ,0 }, 1355 { "sqlite3_config_heap", test_config_heap ,0 }, 1356 { "sqlite3_config_memstatus", test_config_memstatus ,0 }, 1357 { "sqlite3_config_lookaside", test_config_lookaside ,0 }, 1358 { "sqlite3_config_error", test_config_error ,0 }, 1359 { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, 1360 { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, 1361 { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, 1362 }; 1363 int i; 1364 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 1365 ClientData c = (ClientData)aObjCmd[i].clientData; 1366 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); 1367 } 1368 return TCL_OK; 1369 } 1370 #endif 1371