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>