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