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