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