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