Home | History | Annotate | Download | only in src
      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 ** Usage:
   1179 **
   1180 **   sqlite3_dump_memsys3  FILENAME
   1181 **   sqlite3_dump_memsys5  FILENAME
   1182 **
   1183 ** Write a summary of unfreed memsys3 allocations to FILENAME.
   1184 */
   1185 static int test_dump_memsys3(
   1186   void * clientData,
   1187   Tcl_Interp *interp,
   1188   int objc,
   1189   Tcl_Obj *CONST objv[]
   1190 ){
   1191   if( objc!=2 ){
   1192     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
   1193     return TCL_ERROR;
   1194   }
   1195 
   1196   switch( (int)clientData ){
   1197     case 3: {
   1198 #ifdef SQLITE_ENABLE_MEMSYS3
   1199       extern void sqlite3Memsys3Dump(const char*);
   1200       sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
   1201       break;
   1202 #endif
   1203     }
   1204     case 5: {
   1205 #ifdef SQLITE_ENABLE_MEMSYS5
   1206       extern void sqlite3Memsys5Dump(const char*);
   1207       sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
   1208       break;
   1209 #endif
   1210     }
   1211   }
   1212   return TCL_OK;
   1213 }
   1214 
   1215 /*
   1216 ** Usage:    sqlite3_status  OPCODE  RESETFLAG
   1217 **
   1218 ** Return a list of three elements which are the sqlite3_status() return
   1219 ** code, the current value, and the high-water mark value.
   1220 */
   1221 static int test_status(
   1222   void * clientData,
   1223   Tcl_Interp *interp,
   1224   int objc,
   1225   Tcl_Obj *CONST objv[]
   1226 ){
   1227   int rc, iValue, mxValue;
   1228   int i, op, resetFlag;
   1229   const char *zOpName;
   1230   static const struct {
   1231     const char *zName;
   1232     int op;
   1233   } aOp[] = {
   1234     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
   1235     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
   1236     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
   1237     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
   1238     { "SQLITE_STATUS_PAGECACHE_SIZE",      SQLITE_STATUS_PAGECACHE_SIZE      },
   1239     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
   1240     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
   1241     { "SQLITE_STATUS_SCRATCH_SIZE",        SQLITE_STATUS_SCRATCH_SIZE        },
   1242     { "SQLITE_STATUS_PARSER_STACK",        SQLITE_STATUS_PARSER_STACK        },
   1243     { "SQLITE_STATUS_MALLOC_COUNT",        SQLITE_STATUS_MALLOC_COUNT        },
   1244   };
   1245   Tcl_Obj *pResult;
   1246   if( objc!=3 ){
   1247     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
   1248     return TCL_ERROR;
   1249   }
   1250   zOpName = Tcl_GetString(objv[1]);
   1251   for(i=0; i<ArraySize(aOp); i++){
   1252     if( strcmp(aOp[i].zName, zOpName)==0 ){
   1253       op = aOp[i].op;
   1254       break;
   1255     }
   1256   }
   1257   if( i>=ArraySize(aOp) ){
   1258     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
   1259   }
   1260   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
   1261   iValue = 0;
   1262   mxValue = 0;
   1263   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
   1264   pResult = Tcl_NewObj();
   1265   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
   1266   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
   1267   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
   1268   Tcl_SetObjResult(interp, pResult);
   1269   return TCL_OK;
   1270 }
   1271 
   1272 /*
   1273 ** Usage:    sqlite3_db_status  DATABASE  OPCODE  RESETFLAG
   1274 **
   1275 ** Return a list of three elements which are the sqlite3_db_status() return
   1276 ** code, the current value, and the high-water mark value.
   1277 */
   1278 static int test_db_status(
   1279   void * clientData,
   1280   Tcl_Interp *interp,
   1281   int objc,
   1282   Tcl_Obj *CONST objv[]
   1283 ){
   1284   int rc, iValue, mxValue;
   1285   int i, op, resetFlag;
   1286   const char *zOpName;
   1287   sqlite3 *db;
   1288   int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
   1289   static const struct {
   1290     const char *zName;
   1291     int op;
   1292   } aOp[] = {
   1293     { "LOOKASIDE_USED",      SQLITE_DBSTATUS_LOOKASIDE_USED      },
   1294     { "CACHE_USED",          SQLITE_DBSTATUS_CACHE_USED          },
   1295     { "SCHEMA_USED",         SQLITE_DBSTATUS_SCHEMA_USED         },
   1296     { "STMT_USED",           SQLITE_DBSTATUS_STMT_USED           },
   1297     { "LOOKASIDE_HIT",       SQLITE_DBSTATUS_LOOKASIDE_HIT       },
   1298     { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
   1299     { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }
   1300   };
   1301   Tcl_Obj *pResult;
   1302   if( objc!=4 ){
   1303     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
   1304     return TCL_ERROR;
   1305   }
   1306   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
   1307   zOpName = Tcl_GetString(objv[2]);
   1308   if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
   1309   if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
   1310   for(i=0; i<ArraySize(aOp); i++){
   1311     if( strcmp(aOp[i].zName, zOpName)==0 ){
   1312       op = aOp[i].op;
   1313       break;
   1314     }
   1315   }
   1316   if( i>=ArraySize(aOp) ){
   1317     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
   1318   }
   1319   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
   1320   iValue = 0;
   1321   mxValue = 0;
   1322   rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
   1323   pResult = Tcl_NewObj();
   1324   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
   1325   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
   1326   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
   1327   Tcl_SetObjResult(interp, pResult);
   1328   return TCL_OK;
   1329 }
   1330 
   1331 /*
   1332 ** install_malloc_faultsim BOOLEAN
   1333 */
   1334 static int test_install_malloc_faultsim(
   1335   void * clientData,
   1336   Tcl_Interp *interp,
   1337   int objc,
   1338   Tcl_Obj *CONST objv[]
   1339 ){
   1340   int rc;
   1341   int isInstall;
   1342 
   1343   if( objc!=2 ){
   1344     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
   1345     return TCL_ERROR;
   1346   }
   1347   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
   1348     return TCL_ERROR;
   1349   }
   1350   rc = faultsimInstall(isInstall);
   1351   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
   1352   return TCL_OK;
   1353 }
   1354 
   1355 /*
   1356 ** sqlite3_install_memsys3
   1357 */
   1358 static int test_install_memsys3(
   1359   void * clientData,
   1360   Tcl_Interp *interp,
   1361   int objc,
   1362   Tcl_Obj *CONST objv[]
   1363 ){
   1364   int rc = SQLITE_MISUSE;
   1365 #ifdef SQLITE_ENABLE_MEMSYS3
   1366   const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
   1367   rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
   1368 #endif
   1369   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
   1370   return TCL_OK;
   1371 }
   1372 
   1373 static int test_vfs_oom_test(
   1374   void * clientData,
   1375   Tcl_Interp *interp,
   1376   int objc,
   1377   Tcl_Obj *CONST objv[]
   1378 ){
   1379   extern int sqlite3_memdebug_vfs_oom_test;
   1380   if( objc>2 ){
   1381     Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
   1382     return TCL_ERROR;
   1383   }else if( objc==2 ){
   1384     int iNew;
   1385     if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
   1386     sqlite3_memdebug_vfs_oom_test = iNew;
   1387   }
   1388   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
   1389   return TCL_OK;
   1390 }
   1391 
   1392 /*
   1393 ** Register commands with the TCL interpreter.
   1394 */
   1395 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
   1396   static struct {
   1397      char *zName;
   1398      Tcl_ObjCmdProc *xProc;
   1399      int clientData;
   1400   } aObjCmd[] = {
   1401      { "sqlite3_malloc",             test_malloc                   ,0 },
   1402      { "sqlite3_realloc",            test_realloc                  ,0 },
   1403      { "sqlite3_free",               test_free                     ,0 },
   1404      { "memset",                     test_memset                   ,0 },
   1405      { "memget",                     test_memget                   ,0 },
   1406      { "sqlite3_memory_used",        test_memory_used              ,0 },
   1407      { "sqlite3_memory_highwater",   test_memory_highwater         ,0 },
   1408      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       ,0 },
   1409      { "sqlite3_memdebug_dump",      test_memdebug_dump            ,0 },
   1410      { "sqlite3_memdebug_fail",      test_memdebug_fail            ,0 },
   1411      { "sqlite3_memdebug_pending",   test_memdebug_pending         ,0 },
   1412      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        ,0 },
   1413      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
   1414      { "sqlite3_memdebug_log",       test_memdebug_log             ,0 },
   1415      { "sqlite3_config_scratch",     test_config_scratch           ,0 },
   1416      { "sqlite3_config_pagecache",   test_config_pagecache         ,0 },
   1417      { "sqlite3_config_alt_pcache",  test_alt_pcache               ,0 },
   1418      { "sqlite3_status",             test_status                   ,0 },
   1419      { "sqlite3_db_status",          test_db_status                ,0 },
   1420      { "install_malloc_faultsim",    test_install_malloc_faultsim  ,0 },
   1421      { "sqlite3_config_heap",        test_config_heap              ,0 },
   1422      { "sqlite3_config_memstatus",   test_config_memstatus         ,0 },
   1423      { "sqlite3_config_lookaside",   test_config_lookaside         ,0 },
   1424      { "sqlite3_config_error",       test_config_error             ,0 },
   1425      { "sqlite3_db_config_lookaside",test_db_config_lookaside      ,0 },
   1426      { "sqlite3_dump_memsys3",       test_dump_memsys3             ,3 },
   1427      { "sqlite3_dump_memsys5",       test_dump_memsys3             ,5 },
   1428      { "sqlite3_install_memsys3",    test_install_memsys3          ,0 },
   1429      { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test          ,0 },
   1430   };
   1431   int i;
   1432   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
   1433     ClientData c = (ClientData)aObjCmd[i].clientData;
   1434     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
   1435   }
   1436   return TCL_OK;
   1437 }
   1438 #endif
   1439