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