modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_malloc.c (about)

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