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