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