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