File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / src / test_malloc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 8 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>