xref: /sqlite-3.40.0/src/test_malloc.c (revision d09414cd)
12f999a67Sdrh /*
22f999a67Sdrh ** 2007 August 15
32f999a67Sdrh **
42f999a67Sdrh ** The author disclaims copyright to this source code.  In place of
52f999a67Sdrh ** a legal notice, here is a blessing:
62f999a67Sdrh **
72f999a67Sdrh **    May you do good and not evil.
82f999a67Sdrh **    May you find forgiveness for yourself and forgive others.
92f999a67Sdrh **    May you share freely, never taking more than you give.
102f999a67Sdrh **
112f999a67Sdrh *************************************************************************
122f999a67Sdrh **
132f999a67Sdrh ** This file contains code used to implement test interfaces to the
142f999a67Sdrh ** memory allocation subsystem.
152f999a67Sdrh **
16*d09414cdSdanielk1977 ** $Id: test_malloc.c,v 1.26 2008/06/19 18:17:50 danielk1977 Exp $
172f999a67Sdrh */
182f999a67Sdrh #include "sqliteInt.h"
192f999a67Sdrh #include "tcl.h"
202f999a67Sdrh #include <stdlib.h>
212f999a67Sdrh #include <string.h>
222f999a67Sdrh #include <assert.h>
232f999a67Sdrh 
24*d09414cdSdanielk1977 const char *sqlite3TestErrorName(int);
25*d09414cdSdanielk1977 
262f999a67Sdrh /*
272f999a67Sdrh ** Transform pointers to text and back again
282f999a67Sdrh */
292f999a67Sdrh static void pointerToText(void *p, char *z){
302f999a67Sdrh   static const char zHex[] = "0123456789abcdef";
312f999a67Sdrh   int i, k;
324a50aac5Sdrh   unsigned int u;
334a50aac5Sdrh   sqlite3_uint64 n;
344a50aac5Sdrh   if( sizeof(n)==sizeof(p) ){
354a50aac5Sdrh     memcpy(&n, &p, sizeof(p));
364a50aac5Sdrh   }else if( sizeof(u)==sizeof(p) ){
374a50aac5Sdrh     memcpy(&u, &p, sizeof(u));
384a50aac5Sdrh     n = u;
394a50aac5Sdrh   }else{
404a50aac5Sdrh     assert( 0 );
414a50aac5Sdrh   }
422f999a67Sdrh   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
432f999a67Sdrh     z[k] = zHex[n&0xf];
442f999a67Sdrh     n >>= 4;
452f999a67Sdrh   }
462f999a67Sdrh   z[sizeof(p)*2] = 0;
472f999a67Sdrh }
482f999a67Sdrh static int hexToInt(int h){
492f999a67Sdrh   if( h>='0' && h<='9' ){
502f999a67Sdrh     return h - '0';
512f999a67Sdrh   }else if( h>='a' && h<='f' ){
522f999a67Sdrh     return h - 'a' + 10;
532f999a67Sdrh   }else{
542f999a67Sdrh     return -1;
552f999a67Sdrh   }
562f999a67Sdrh }
572f999a67Sdrh static int textToPointer(const char *z, void **pp){
582f999a67Sdrh   sqlite3_uint64 n = 0;
592f999a67Sdrh   int i;
604a50aac5Sdrh   unsigned int u;
612f999a67Sdrh   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
622f999a67Sdrh     int v;
632f999a67Sdrh     v = hexToInt(*z++);
642f999a67Sdrh     if( v<0 ) return TCL_ERROR;
652f999a67Sdrh     n = n*16 + v;
662f999a67Sdrh   }
672f999a67Sdrh   if( *z!=0 ) return TCL_ERROR;
684a50aac5Sdrh   if( sizeof(n)==sizeof(*pp) ){
694a50aac5Sdrh     memcpy(pp, &n, sizeof(n));
704a50aac5Sdrh   }else if( sizeof(u)==sizeof(*pp) ){
714a50aac5Sdrh     u = (unsigned int)n;
724a50aac5Sdrh     memcpy(pp, &u, sizeof(u));
734a50aac5Sdrh   }else{
744a50aac5Sdrh     assert( 0 );
754a50aac5Sdrh   }
762f999a67Sdrh   return TCL_OK;
772f999a67Sdrh }
782f999a67Sdrh 
792f999a67Sdrh /*
802f999a67Sdrh ** Usage:    sqlite3_malloc  NBYTES
812f999a67Sdrh **
822f999a67Sdrh ** Raw test interface for sqlite3_malloc().
832f999a67Sdrh */
842f999a67Sdrh static int test_malloc(
852f999a67Sdrh   void * clientData,
862f999a67Sdrh   Tcl_Interp *interp,
872f999a67Sdrh   int objc,
882f999a67Sdrh   Tcl_Obj *CONST objv[]
892f999a67Sdrh ){
902f999a67Sdrh   int nByte;
912f999a67Sdrh   void *p;
922f999a67Sdrh   char zOut[100];
932f999a67Sdrh   if( objc!=2 ){
942f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
952f999a67Sdrh     return TCL_ERROR;
962f999a67Sdrh   }
972f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
982f999a67Sdrh   p = sqlite3_malloc((unsigned)nByte);
992f999a67Sdrh   pointerToText(p, zOut);
1002f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
1012f999a67Sdrh   return TCL_OK;
1022f999a67Sdrh }
1032f999a67Sdrh 
1042f999a67Sdrh /*
1052f999a67Sdrh ** Usage:    sqlite3_realloc  PRIOR  NBYTES
1062f999a67Sdrh **
1072f999a67Sdrh ** Raw test interface for sqlite3_realloc().
1082f999a67Sdrh */
1092f999a67Sdrh static int test_realloc(
1102f999a67Sdrh   void * clientData,
1112f999a67Sdrh   Tcl_Interp *interp,
1122f999a67Sdrh   int objc,
1132f999a67Sdrh   Tcl_Obj *CONST objv[]
1142f999a67Sdrh ){
1152f999a67Sdrh   int nByte;
1162f999a67Sdrh   void *pPrior, *p;
1172f999a67Sdrh   char zOut[100];
1182f999a67Sdrh   if( objc!=3 ){
1192f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
1202f999a67Sdrh     return TCL_ERROR;
1212f999a67Sdrh   }
1222f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
1232f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
1242f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
1252f999a67Sdrh     return TCL_ERROR;
1262f999a67Sdrh   }
1272f999a67Sdrh   p = sqlite3_realloc(pPrior, (unsigned)nByte);
1282f999a67Sdrh   pointerToText(p, zOut);
1292f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
1302f999a67Sdrh   return TCL_OK;
1312f999a67Sdrh }
1322f999a67Sdrh 
1332f999a67Sdrh 
1342f999a67Sdrh /*
1352f999a67Sdrh ** Usage:    sqlite3_free  PRIOR
1362f999a67Sdrh **
1372f999a67Sdrh ** Raw test interface for sqlite3_free().
1382f999a67Sdrh */
1392f999a67Sdrh static int test_free(
1402f999a67Sdrh   void * clientData,
1412f999a67Sdrh   Tcl_Interp *interp,
1422f999a67Sdrh   int objc,
1432f999a67Sdrh   Tcl_Obj *CONST objv[]
1442f999a67Sdrh ){
1452f999a67Sdrh   void *pPrior;
1462f999a67Sdrh   if( objc!=2 ){
1472f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
1482f999a67Sdrh     return TCL_ERROR;
1492f999a67Sdrh   }
1502f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
1512f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
1522f999a67Sdrh     return TCL_ERROR;
1532f999a67Sdrh   }
1542f999a67Sdrh   sqlite3_free(pPrior);
1552f999a67Sdrh   return TCL_OK;
1562f999a67Sdrh }
1572f999a67Sdrh 
1582f999a67Sdrh /*
1599c7a60dfSdrh ** These routines are in test_hexio.c
1609c7a60dfSdrh */
1619c7a60dfSdrh int sqlite3TestHexToBin(const char *, int, char *);
1629c7a60dfSdrh int sqlite3TestBinToHex(char*,int);
1639c7a60dfSdrh 
1649c7a60dfSdrh /*
1659c7a60dfSdrh ** Usage:    memset  ADDRESS  SIZE  HEX
1669c7a60dfSdrh **
1679c7a60dfSdrh ** Set a chunk of memory (obtained from malloc, probably) to a
1689c7a60dfSdrh ** specified hex pattern.
1699c7a60dfSdrh */
1709c7a60dfSdrh static int test_memset(
1719c7a60dfSdrh   void * clientData,
1729c7a60dfSdrh   Tcl_Interp *interp,
1739c7a60dfSdrh   int objc,
1749c7a60dfSdrh   Tcl_Obj *CONST objv[]
1759c7a60dfSdrh ){
1769c7a60dfSdrh   void *p;
1779c7a60dfSdrh   int size, n, i;
1789c7a60dfSdrh   char *zHex;
1799c7a60dfSdrh   char *zOut;
1809c7a60dfSdrh   char zBin[100];
1819c7a60dfSdrh 
1829c7a60dfSdrh   if( objc!=4 ){
1839c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
1849c7a60dfSdrh     return TCL_ERROR;
1859c7a60dfSdrh   }
1869c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
1879c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
1889c7a60dfSdrh     return TCL_ERROR;
1899c7a60dfSdrh   }
1909c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
1919c7a60dfSdrh     return TCL_ERROR;
1929c7a60dfSdrh   }
1939c7a60dfSdrh   if( size<=0 ){
1949c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
1959c7a60dfSdrh     return TCL_ERROR;
1969c7a60dfSdrh   }
1979c7a60dfSdrh   zHex = Tcl_GetStringFromObj(objv[3], &n);
1989c7a60dfSdrh   if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
1999c7a60dfSdrh   n = sqlite3TestHexToBin(zHex, n, zBin);
2009c7a60dfSdrh   if( n==0 ){
2019c7a60dfSdrh     Tcl_AppendResult(interp, "no data", (char*)0);
2029c7a60dfSdrh     return TCL_ERROR;
2039c7a60dfSdrh   }
2049c7a60dfSdrh   zOut = p;
2059c7a60dfSdrh   for(i=0; i<size; i++){
2069c7a60dfSdrh     zOut[i] = zBin[i%n];
2079c7a60dfSdrh   }
2089c7a60dfSdrh   return TCL_OK;
2099c7a60dfSdrh }
2109c7a60dfSdrh 
2119c7a60dfSdrh /*
2129c7a60dfSdrh ** Usage:    memget  ADDRESS  SIZE
2139c7a60dfSdrh **
2149c7a60dfSdrh ** Return memory as hexadecimal text.
2159c7a60dfSdrh */
2169c7a60dfSdrh static int test_memget(
2179c7a60dfSdrh   void * clientData,
2189c7a60dfSdrh   Tcl_Interp *interp,
2199c7a60dfSdrh   int objc,
2209c7a60dfSdrh   Tcl_Obj *CONST objv[]
2219c7a60dfSdrh ){
2229c7a60dfSdrh   void *p;
2239c7a60dfSdrh   int size, n;
2249c7a60dfSdrh   char *zBin;
2259c7a60dfSdrh   char zHex[100];
2269c7a60dfSdrh 
2279c7a60dfSdrh   if( objc!=3 ){
2289c7a60dfSdrh     Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
2299c7a60dfSdrh     return TCL_ERROR;
2309c7a60dfSdrh   }
2319c7a60dfSdrh   if( textToPointer(Tcl_GetString(objv[1]), &p) ){
2329c7a60dfSdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
2339c7a60dfSdrh     return TCL_ERROR;
2349c7a60dfSdrh   }
2359c7a60dfSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
2369c7a60dfSdrh     return TCL_ERROR;
2379c7a60dfSdrh   }
2389c7a60dfSdrh   if( size<=0 ){
2399c7a60dfSdrh     Tcl_AppendResult(interp, "size must be positive", (char*)0);
2409c7a60dfSdrh     return TCL_ERROR;
2419c7a60dfSdrh   }
2429c7a60dfSdrh   zBin = p;
2439c7a60dfSdrh   while( size>0 ){
2449c7a60dfSdrh     if( size>(sizeof(zHex)-1)/2 ){
2459c7a60dfSdrh       n = (sizeof(zHex)-1)/2;
2469c7a60dfSdrh     }else{
2479c7a60dfSdrh       n = size;
2489c7a60dfSdrh     }
2499c7a60dfSdrh     memcpy(zHex, zBin, n);
2509c7a60dfSdrh     zBin += n;
2519c7a60dfSdrh     size -= n;
2529c7a60dfSdrh     sqlite3TestBinToHex(zHex, n);
2539c7a60dfSdrh     Tcl_AppendResult(interp, zHex, (char*)0);
2549c7a60dfSdrh   }
2559c7a60dfSdrh   return TCL_OK;
2569c7a60dfSdrh }
2579c7a60dfSdrh 
2589c7a60dfSdrh /*
2592f999a67Sdrh ** Usage:    sqlite3_memory_used
2602f999a67Sdrh **
2612f999a67Sdrh ** Raw test interface for sqlite3_memory_used().
2622f999a67Sdrh */
2632f999a67Sdrh static int test_memory_used(
2642f999a67Sdrh   void * clientData,
2652f999a67Sdrh   Tcl_Interp *interp,
2662f999a67Sdrh   int objc,
2672f999a67Sdrh   Tcl_Obj *CONST objv[]
2682f999a67Sdrh ){
2692f999a67Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
2702f999a67Sdrh   return TCL_OK;
2712f999a67Sdrh }
2722f999a67Sdrh 
2732f999a67Sdrh /*
2742f999a67Sdrh ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
2752f999a67Sdrh **
2762f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater().
2772f999a67Sdrh */
2782f999a67Sdrh static int test_memory_highwater(
2792f999a67Sdrh   void * clientData,
2802f999a67Sdrh   Tcl_Interp *interp,
2812f999a67Sdrh   int objc,
2822f999a67Sdrh   Tcl_Obj *CONST objv[]
2832f999a67Sdrh ){
2842f999a67Sdrh   int resetFlag = 0;
2852f999a67Sdrh   if( objc!=1 && objc!=2 ){
2862f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
2872f999a67Sdrh     return TCL_ERROR;
2882f999a67Sdrh   }
2892f999a67Sdrh   if( objc==2 ){
2902f999a67Sdrh     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
2912f999a67Sdrh   }
2922f999a67Sdrh   Tcl_SetObjResult(interp,
2932f999a67Sdrh      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
2942f999a67Sdrh   return TCL_OK;
2952f999a67Sdrh }
2962f999a67Sdrh 
2972f999a67Sdrh /*
2982f999a67Sdrh ** Usage:    sqlite3_memdebug_backtrace DEPTH
2992f999a67Sdrh **
3002f999a67Sdrh ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
3012f999a67Sdrh ** then this routine is a no-op.
3022f999a67Sdrh */
3032f999a67Sdrh static int test_memdebug_backtrace(
3042f999a67Sdrh   void * clientData,
3052f999a67Sdrh   Tcl_Interp *interp,
3062f999a67Sdrh   int objc,
3072f999a67Sdrh   Tcl_Obj *CONST objv[]
3082f999a67Sdrh ){
3092f999a67Sdrh   int depth;
3102f999a67Sdrh   if( objc!=2 ){
3112f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
3122f999a67Sdrh     return TCL_ERROR;
3132f999a67Sdrh   }
3142f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
3152f999a67Sdrh #ifdef SQLITE_MEMDEBUG
3162f999a67Sdrh   {
31749e4fd71Sdrh     extern void sqlite3MemdebugBacktrace(int);
31849e4fd71Sdrh     sqlite3MemdebugBacktrace(depth);
3192f999a67Sdrh   }
3202f999a67Sdrh #endif
3212f999a67Sdrh   return TCL_OK;
3222f999a67Sdrh }
3232f999a67Sdrh 
3242f999a67Sdrh /*
3252f999a67Sdrh ** Usage:    sqlite3_memdebug_dump  FILENAME
3262f999a67Sdrh **
3272f999a67Sdrh ** Write a summary of unfreed memory to FILENAME.
3282f999a67Sdrh */
3292f999a67Sdrh static int test_memdebug_dump(
3302f999a67Sdrh   void * clientData,
3312f999a67Sdrh   Tcl_Interp *interp,
3322f999a67Sdrh   int objc,
3332f999a67Sdrh   Tcl_Obj *CONST objv[]
3342f999a67Sdrh ){
3352f999a67Sdrh   if( objc!=2 ){
3362f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
3372f999a67Sdrh     return TCL_ERROR;
3382f999a67Sdrh   }
3392d7636e2Sdrh #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
3402d7636e2Sdrh      || defined(SQLITE_POW2_MEMORY_SIZE)
3412f999a67Sdrh   {
34249e4fd71Sdrh     extern void sqlite3MemdebugDump(const char*);
34349e4fd71Sdrh     sqlite3MemdebugDump(Tcl_GetString(objv[1]));
3442f999a67Sdrh   }
3452f999a67Sdrh #endif
3462f999a67Sdrh   return TCL_OK;
3472f999a67Sdrh }
3482f999a67Sdrh 
349a7a8e14bSdanielk1977 /*
350a7a8e14bSdanielk1977 ** Usage:    sqlite3_memdebug_malloc_count
351a7a8e14bSdanielk1977 **
352a7a8e14bSdanielk1977 ** Return the total number of times malloc() has been called.
353a7a8e14bSdanielk1977 */
354a7a8e14bSdanielk1977 static int test_memdebug_malloc_count(
355a7a8e14bSdanielk1977   void * clientData,
356a7a8e14bSdanielk1977   Tcl_Interp *interp,
357a7a8e14bSdanielk1977   int objc,
358a7a8e14bSdanielk1977   Tcl_Obj *CONST objv[]
359a7a8e14bSdanielk1977 ){
360a7a8e14bSdanielk1977   int nMalloc = -1;
361a7a8e14bSdanielk1977   if( objc!=1 ){
362a7a8e14bSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
363a7a8e14bSdanielk1977     return TCL_ERROR;
364a7a8e14bSdanielk1977   }
365a7a8e14bSdanielk1977 #if defined(SQLITE_MEMDEBUG)
366a7a8e14bSdanielk1977   {
36749e4fd71Sdrh     extern int sqlite3MemdebugMallocCount();
36849e4fd71Sdrh     nMalloc = sqlite3MemdebugMallocCount();
369a7a8e14bSdanielk1977   }
370a7a8e14bSdanielk1977 #endif
371a7a8e14bSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
372a7a8e14bSdanielk1977   return TCL_OK;
373a7a8e14bSdanielk1977 }
374a7a8e14bSdanielk1977 
3752f999a67Sdrh 
3762f999a67Sdrh /*
377a1644fd8Sdanielk1977 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
378a1644fd8Sdanielk1977 **
379a1644fd8Sdanielk1977 ** where options are:
380a1644fd8Sdanielk1977 **
381643167ffSdrh **     -repeat    <count>
382a1644fd8Sdanielk1977 **     -benigncnt <varname>
3830e6f1546Sdrh **
3840e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes.
385643167ffSdrh ** If a repeat count is specified, the fault is repeated that many
386643167ffSdrh ** times.
3870e6f1546Sdrh **
3880e6f1546Sdrh ** Each call to this routine overrides the prior counter value.
3890e6f1546Sdrh ** This routine returns the number of simulated failures that have
3900e6f1546Sdrh ** happened since the previous call to this routine.
3910e6f1546Sdrh **
3920e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1.
3930e6f1546Sdrh */
3940e6f1546Sdrh static int test_memdebug_fail(
3950e6f1546Sdrh   void * clientData,
3960e6f1546Sdrh   Tcl_Interp *interp,
3970e6f1546Sdrh   int objc,
3980e6f1546Sdrh   Tcl_Obj *CONST objv[]
3990e6f1546Sdrh ){
400a1644fd8Sdanielk1977   int ii;
4010e6f1546Sdrh   int iFail;
402643167ffSdrh   int nRepeat = 1;
403a1644fd8Sdanielk1977   Tcl_Obj *pBenignCnt = 0;
404643167ffSdrh   int nBenign;
4050e6f1546Sdrh   int nFail = 0;
406a1644fd8Sdanielk1977 
407a1644fd8Sdanielk1977   if( objc<2 ){
408a1644fd8Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
4090e6f1546Sdrh     return TCL_ERROR;
4100e6f1546Sdrh   }
4110e6f1546Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
412a1644fd8Sdanielk1977 
413a1644fd8Sdanielk1977   for(ii=2; ii<objc; ii+=2){
414a1644fd8Sdanielk1977     int nOption;
415a1644fd8Sdanielk1977     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
416a1644fd8Sdanielk1977     char *zErr = 0;
417a1644fd8Sdanielk1977 
418a1644fd8Sdanielk1977     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
419a1644fd8Sdanielk1977       if( ii==(objc-1) ){
420a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
421ed138fb3Sdrh       }else{
422643167ffSdrh         if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
423a1644fd8Sdanielk1977           return TCL_ERROR;
424ed138fb3Sdrh         }
425a1644fd8Sdanielk1977       }
426a1644fd8Sdanielk1977     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
427a1644fd8Sdanielk1977       if( ii==(objc-1) ){
428a1644fd8Sdanielk1977         zErr = "option requires an argument: ";
429a1644fd8Sdanielk1977       }else{
430a1644fd8Sdanielk1977         pBenignCnt = objv[ii+1];
431a1644fd8Sdanielk1977       }
432a1644fd8Sdanielk1977     }else{
433a1644fd8Sdanielk1977       zErr = "unknown option: ";
434a1644fd8Sdanielk1977     }
435a1644fd8Sdanielk1977 
436a1644fd8Sdanielk1977     if( zErr ){
437a1644fd8Sdanielk1977       Tcl_AppendResult(interp, zErr, zOption, 0);
438a1644fd8Sdanielk1977       return TCL_ERROR;
439a1644fd8Sdanielk1977     }
440a1644fd8Sdanielk1977   }
441a1644fd8Sdanielk1977 
44277db4c05Sdrh   sqlite3_test_control(-12345); /* Just to stress the test_control interface */
443ed13d98cSdrh   nBenign = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES,
444ed13d98cSdrh                                  SQLITE_FAULTINJECTOR_MALLOC);
445ed13d98cSdrh   nFail = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_FAILURES,
446ed13d98cSdrh                                SQLITE_FAULTINJECTOR_MALLOC);
447ed13d98cSdrh   sqlite3_test_control(SQLITE_TESTCTRL_FAULT_CONFIG,
448ed13d98cSdrh                        SQLITE_FAULTINJECTOR_MALLOC, iFail, nRepeat);
449a1644fd8Sdanielk1977   if( pBenignCnt ){
450643167ffSdrh     Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
451a1644fd8Sdanielk1977   }
4520e6f1546Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
4530e6f1546Sdrh   return TCL_OK;
4540e6f1546Sdrh }
4550e6f1546Sdrh 
456cd03724cSdanielk1977 /*
457cd03724cSdanielk1977 ** Usage:    sqlite3_memdebug_pending
458cd03724cSdanielk1977 **
459cd03724cSdanielk1977 ** Return the number of malloc() calls that will succeed before a
460cd03724cSdanielk1977 ** simulated failure occurs. A negative return value indicates that
461cd03724cSdanielk1977 ** no malloc() failure is scheduled.
462cd03724cSdanielk1977 */
463cd03724cSdanielk1977 static int test_memdebug_pending(
464cd03724cSdanielk1977   void * clientData,
465cd03724cSdanielk1977   Tcl_Interp *interp,
466cd03724cSdanielk1977   int objc,
467cd03724cSdanielk1977   Tcl_Obj *CONST objv[]
468cd03724cSdanielk1977 ){
4695efaf070Sdrh   int nPending;
470cd03724cSdanielk1977   if( objc!=1 ){
471cd03724cSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
472cd03724cSdanielk1977     return TCL_ERROR;
473cd03724cSdanielk1977   }
4745efaf070Sdrh   nPending = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_PENDING,
475ed13d98cSdrh                                   SQLITE_FAULTINJECTOR_MALLOC);
476ed13d98cSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
477cd03724cSdanielk1977   return TCL_OK;
478cd03724cSdanielk1977 }
479cd03724cSdanielk1977 
4800e6f1546Sdrh 
4810e6f1546Sdrh /*
4824a50aac5Sdrh ** Usage:    sqlite3_memdebug_settitle TITLE
4834a50aac5Sdrh **
4844a50aac5Sdrh ** Set a title string stored with each allocation.  The TITLE is
4854a50aac5Sdrh ** typically the name of the test that was running when the
4864a50aac5Sdrh ** allocation occurred.  The TITLE is stored with the allocation
4874a50aac5Sdrh ** and can be used to figure out which tests are leaking memory.
4884a50aac5Sdrh **
4894a50aac5Sdrh ** Each title overwrite the previous.
4904a50aac5Sdrh */
4914a50aac5Sdrh static int test_memdebug_settitle(
4924a50aac5Sdrh   void * clientData,
4934a50aac5Sdrh   Tcl_Interp *interp,
4944a50aac5Sdrh   int objc,
4954a50aac5Sdrh   Tcl_Obj *CONST objv[]
4964a50aac5Sdrh ){
4974a50aac5Sdrh   const char *zTitle;
4984a50aac5Sdrh   if( objc!=2 ){
4994a50aac5Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
5004a50aac5Sdrh     return TCL_ERROR;
5014a50aac5Sdrh   }
5024a50aac5Sdrh   zTitle = Tcl_GetString(objv[1]);
5034a50aac5Sdrh #ifdef SQLITE_MEMDEBUG
5044a50aac5Sdrh   {
50549e4fd71Sdrh     extern int sqlite3MemdebugSettitle(const char*);
50649e4fd71Sdrh     sqlite3MemdebugSettitle(zTitle);
5074a50aac5Sdrh   }
5084a50aac5Sdrh #endif
5094a50aac5Sdrh   return TCL_OK;
5104a50aac5Sdrh }
5114a50aac5Sdrh 
512cd3e8f7cSdanielk1977 #define MALLOC_LOG_FRAMES 10
5136f332c18Sdanielk1977 static Tcl_HashTable aMallocLog;
5146f332c18Sdanielk1977 static int mallocLogEnabled = 0;
5156f332c18Sdanielk1977 
5166f332c18Sdanielk1977 typedef struct MallocLog MallocLog;
5176f332c18Sdanielk1977 struct MallocLog {
5186f332c18Sdanielk1977   int nCall;
5196f332c18Sdanielk1977   int nByte;
5206f332c18Sdanielk1977 };
5216f332c18Sdanielk1977 
522afdd23a4Sshane #ifdef SQLITE_MEMDEBUG
5236f332c18Sdanielk1977 static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
5246f332c18Sdanielk1977   if( mallocLogEnabled ){
5256f332c18Sdanielk1977     MallocLog *pLog;
5266f332c18Sdanielk1977     Tcl_HashEntry *pEntry;
5276f332c18Sdanielk1977     int isNew;
5286f332c18Sdanielk1977 
5296f332c18Sdanielk1977     int aKey[MALLOC_LOG_FRAMES];
5306f332c18Sdanielk1977     int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
5316f332c18Sdanielk1977 
5326f332c18Sdanielk1977     memset(aKey, 0, nKey);
5336f332c18Sdanielk1977     if( (sizeof(void*)*nFrame)<nKey ){
5346f332c18Sdanielk1977       nKey = nFrame*sizeof(void*);
5356f332c18Sdanielk1977     }
5366f332c18Sdanielk1977     memcpy(aKey, aFrame, nKey);
5376f332c18Sdanielk1977 
5386f332c18Sdanielk1977     pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
5396f332c18Sdanielk1977     if( isNew ){
5406f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
5416f332c18Sdanielk1977       memset(pLog, 0, sizeof(MallocLog));
5426f332c18Sdanielk1977       Tcl_SetHashValue(pEntry, (ClientData)pLog);
5436f332c18Sdanielk1977     }else{
5446f332c18Sdanielk1977       pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
5456f332c18Sdanielk1977     }
5466f332c18Sdanielk1977 
5476f332c18Sdanielk1977     pLog->nCall++;
5486f332c18Sdanielk1977     pLog->nByte += nByte;
5496f332c18Sdanielk1977   }
5506f332c18Sdanielk1977 }
551afdd23a4Sshane #endif /* SQLITE_MEMDEBUG */
5526f332c18Sdanielk1977 
5535f096135Sdanielk1977 static void test_memdebug_log_clear(){
554dbdc4d49Sdanielk1977   Tcl_HashSearch search;
555dbdc4d49Sdanielk1977   Tcl_HashEntry *pEntry;
556dbdc4d49Sdanielk1977   for(
557dbdc4d49Sdanielk1977     pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
558dbdc4d49Sdanielk1977     pEntry;
559dbdc4d49Sdanielk1977     pEntry=Tcl_NextHashEntry(&search)
560dbdc4d49Sdanielk1977   ){
561dbdc4d49Sdanielk1977     MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
562dbdc4d49Sdanielk1977     Tcl_Free((char *)pLog);
563dbdc4d49Sdanielk1977   }
564dbdc4d49Sdanielk1977   Tcl_DeleteHashTable(&aMallocLog);
565dbdc4d49Sdanielk1977   Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
566dbdc4d49Sdanielk1977 }
567dbdc4d49Sdanielk1977 
5686f332c18Sdanielk1977 static int test_memdebug_log(
5696f332c18Sdanielk1977   void * clientData,
5706f332c18Sdanielk1977   Tcl_Interp *interp,
5716f332c18Sdanielk1977   int objc,
5726f332c18Sdanielk1977   Tcl_Obj *CONST objv[]
5736f332c18Sdanielk1977 ){
5746f332c18Sdanielk1977   static int isInit = 0;
5756f332c18Sdanielk1977   int iSub;
5766f332c18Sdanielk1977 
577dbdc4d49Sdanielk1977   static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
578dbdc4d49Sdanielk1977   enum MB_enum {
579dbdc4d49Sdanielk1977       MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
580dbdc4d49Sdanielk1977   };
5816f332c18Sdanielk1977 
5826f332c18Sdanielk1977   if( !isInit ){
5836f332c18Sdanielk1977 #ifdef SQLITE_MEMDEBUG
5846f332c18Sdanielk1977     extern void sqlite3MemdebugBacktraceCallback(
5856f332c18Sdanielk1977         void (*xBacktrace)(int, int, void **));
5866f332c18Sdanielk1977     sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
5876f332c18Sdanielk1977 #endif
5886f332c18Sdanielk1977     Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
5896f332c18Sdanielk1977     isInit = 1;
5906f332c18Sdanielk1977   }
5916f332c18Sdanielk1977 
5926f332c18Sdanielk1977   if( objc<2 ){
5936f332c18Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
5946f332c18Sdanielk1977   }
5956f332c18Sdanielk1977   if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
5966f332c18Sdanielk1977     return TCL_ERROR;
5976f332c18Sdanielk1977   }
5986f332c18Sdanielk1977 
5996f332c18Sdanielk1977   switch( (enum MB_enum)iSub ){
6006f332c18Sdanielk1977     case MB_LOG_START:
6016f332c18Sdanielk1977       mallocLogEnabled = 1;
6026f332c18Sdanielk1977       break;
6036f332c18Sdanielk1977     case MB_LOG_STOP:
6046f332c18Sdanielk1977       mallocLogEnabled = 0;
6056f332c18Sdanielk1977       break;
6066f332c18Sdanielk1977     case MB_LOG_DUMP: {
6076f332c18Sdanielk1977       Tcl_HashSearch search;
6086f332c18Sdanielk1977       Tcl_HashEntry *pEntry;
6096f332c18Sdanielk1977       Tcl_Obj *pRet = Tcl_NewObj();
6106f332c18Sdanielk1977 
6116f332c18Sdanielk1977       assert(sizeof(int)==sizeof(void*));
6126f332c18Sdanielk1977 
6136f332c18Sdanielk1977       for(
6146f332c18Sdanielk1977         pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
6156f332c18Sdanielk1977         pEntry;
6166f332c18Sdanielk1977         pEntry=Tcl_NextHashEntry(&search)
6176f332c18Sdanielk1977       ){
6186f332c18Sdanielk1977         Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
6196f332c18Sdanielk1977         MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
6206f332c18Sdanielk1977         int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
6216f332c18Sdanielk1977         int ii;
6226f332c18Sdanielk1977 
6236f332c18Sdanielk1977         apElem[0] = Tcl_NewIntObj(pLog->nCall);
6246f332c18Sdanielk1977         apElem[1] = Tcl_NewIntObj(pLog->nByte);
6256f332c18Sdanielk1977         for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
6266f332c18Sdanielk1977           apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
6276f332c18Sdanielk1977         }
6286f332c18Sdanielk1977 
6296f332c18Sdanielk1977         Tcl_ListObjAppendElement(interp, pRet,
6306f332c18Sdanielk1977             Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
6316f332c18Sdanielk1977         );
6326f332c18Sdanielk1977       }
6336f332c18Sdanielk1977 
6346f332c18Sdanielk1977       Tcl_SetObjResult(interp, pRet);
6356f332c18Sdanielk1977       break;
6366f332c18Sdanielk1977     }
6376f332c18Sdanielk1977     case MB_LOG_CLEAR: {
638dbdc4d49Sdanielk1977       test_memdebug_log_clear();
639dbdc4d49Sdanielk1977       break;
6406f332c18Sdanielk1977     }
641dbdc4d49Sdanielk1977 
642dbdc4d49Sdanielk1977     case MB_LOG_SYNC: {
643b940492eSdrh #ifdef SQLITE_MEMDEBUG
644dbdc4d49Sdanielk1977       extern void sqlite3MemdebugSync();
645dbdc4d49Sdanielk1977       test_memdebug_log_clear();
646dbdc4d49Sdanielk1977       mallocLogEnabled = 1;
647dbdc4d49Sdanielk1977       sqlite3MemdebugSync();
648b940492eSdrh #endif
649dbdc4d49Sdanielk1977       break;
6506f332c18Sdanielk1977     }
6516f332c18Sdanielk1977   }
6526f332c18Sdanielk1977 
6536f332c18Sdanielk1977   return TCL_OK;
6546f332c18Sdanielk1977 }
6554a50aac5Sdrh 
6564a50aac5Sdrh /*
6579ac3fe97Sdrh ** Usage:    sqlite3_config_scratch SIZE N
6589ac3fe97Sdrh **
6599ac3fe97Sdrh ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
6609ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
6619ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size.
6629ac3fe97Sdrh ** The revised value of N is returned.
6639ac3fe97Sdrh **
6649ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
6659ac3fe97Sdrh */
6669ac3fe97Sdrh static int test_config_scratch(
6679ac3fe97Sdrh   void * clientData,
6689ac3fe97Sdrh   Tcl_Interp *interp,
6699ac3fe97Sdrh   int objc,
6709ac3fe97Sdrh   Tcl_Obj *CONST objv[]
6719ac3fe97Sdrh ){
6729ac3fe97Sdrh   int sz, N, rc;
6739ac3fe97Sdrh   Tcl_Obj *pResult;
674f7141990Sdrh   static char buf[30000];
6759ac3fe97Sdrh   if( objc!=3 ){
6769ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
6779ac3fe97Sdrh     return TCL_ERROR;
6789ac3fe97Sdrh   }
679f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
680f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
6819ac3fe97Sdrh   if( sz<0 ){
6829ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
683f7141990Sdrh   }else{
6849ac3fe97Sdrh     int mx = sizeof(buf)/(sz+4);
6859ac3fe97Sdrh     if( N>mx ) N = mx;
6869ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
6879ac3fe97Sdrh   }
6889ac3fe97Sdrh   pResult = Tcl_NewObj();
6899ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
6909ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
6919ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
6929ac3fe97Sdrh   return TCL_OK;
6939ac3fe97Sdrh }
6949ac3fe97Sdrh 
6959ac3fe97Sdrh /*
6969ac3fe97Sdrh ** Usage:    sqlite3_config_pagecache SIZE N
6979ac3fe97Sdrh **
6989ac3fe97Sdrh ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
6999ac3fe97Sdrh ** The buffer is static and is of limited size.  N might be
7009ac3fe97Sdrh ** adjusted downward as needed to accomodate the requested size.
7019ac3fe97Sdrh ** The revised value of N is returned.
7029ac3fe97Sdrh **
7039ac3fe97Sdrh ** A negative SIZE causes the buffer pointer to be NULL.
7049ac3fe97Sdrh */
7059ac3fe97Sdrh static int test_config_pagecache(
7069ac3fe97Sdrh   void * clientData,
7079ac3fe97Sdrh   Tcl_Interp *interp,
7089ac3fe97Sdrh   int objc,
7099ac3fe97Sdrh   Tcl_Obj *CONST objv[]
7109ac3fe97Sdrh ){
7119ac3fe97Sdrh   int sz, N, rc;
7129ac3fe97Sdrh   Tcl_Obj *pResult;
7139ac3fe97Sdrh   static char buf[100000];
7149ac3fe97Sdrh   if( objc!=3 ){
7159ac3fe97Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
7169ac3fe97Sdrh     return TCL_ERROR;
7179ac3fe97Sdrh   }
718f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
719f7141990Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
7209ac3fe97Sdrh   if( sz<0 ){
721f7141990Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
722f7141990Sdrh   }else{
7239ac3fe97Sdrh     int mx = sizeof(buf)/(sz+4);
7249ac3fe97Sdrh     if( N>mx ) N = mx;
7259ac3fe97Sdrh     rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
7269ac3fe97Sdrh   }
7279ac3fe97Sdrh   pResult = Tcl_NewObj();
7289ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
7299ac3fe97Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
7309ac3fe97Sdrh   Tcl_SetObjResult(interp, pResult);
7319ac3fe97Sdrh   return TCL_OK;
7329ac3fe97Sdrh }
7339ac3fe97Sdrh 
734f7141990Sdrh /*
735f7141990Sdrh ** Usage:    sqlite3_status  OPCODE  RESETFLAG
736f7141990Sdrh **
737f7141990Sdrh ** Return a list of three elements which are the sqlite3_status() return
738f7141990Sdrh ** code, the current value, and the high-water mark value.
739f7141990Sdrh */
740f7141990Sdrh static int test_status(
741f7141990Sdrh   void * clientData,
742f7141990Sdrh   Tcl_Interp *interp,
743f7141990Sdrh   int objc,
744f7141990Sdrh   Tcl_Obj *CONST objv[]
745f7141990Sdrh ){
746f7141990Sdrh   int rc, iValue, mxValue;
747f7141990Sdrh   int i, op, resetFlag;
748f7141990Sdrh   const char *zOpName;
749f7141990Sdrh   static const struct {
750f7141990Sdrh     const char *zName;
751f7141990Sdrh     int op;
752f7141990Sdrh   } aOp[] = {
753f7141990Sdrh     { "SQLITE_STATUS_MEMORY_USED",         SQLITE_STATUS_MEMORY_USED         },
754f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_USED",      SQLITE_STATUS_PAGECACHE_USED      },
755f7141990Sdrh     { "SQLITE_STATUS_PAGECACHE_OVERFLOW",  SQLITE_STATUS_PAGECACHE_OVERFLOW  },
756f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_USED",        SQLITE_STATUS_SCRATCH_USED        },
757f7141990Sdrh     { "SQLITE_STATUS_SCRATCH_OVERFLOW",    SQLITE_STATUS_SCRATCH_OVERFLOW    },
758f7141990Sdrh     { "SQLITE_STATUS_MALLOC_SIZE",         SQLITE_STATUS_MALLOC_SIZE         },
759f7141990Sdrh   };
760f7141990Sdrh   Tcl_Obj *pResult;
761f7141990Sdrh   if( objc!=3 ){
762f7141990Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
763f7141990Sdrh     return TCL_ERROR;
764f7141990Sdrh   }
765f7141990Sdrh   zOpName = Tcl_GetString(objv[1]);
766f7141990Sdrh   for(i=0; i<ArraySize(aOp); i++){
767f7141990Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
768f7141990Sdrh       op = aOp[i].op;
769f7141990Sdrh       break;
770f7141990Sdrh     }
771f7141990Sdrh   }
772f7141990Sdrh   if( i>=ArraySize(aOp) ){
773f7141990Sdrh     if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
774f7141990Sdrh   }
775f7141990Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
776f7141990Sdrh   rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
777f7141990Sdrh   pResult = Tcl_NewObj();
778f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
779f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
780f7141990Sdrh   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
781f7141990Sdrh   Tcl_SetObjResult(interp, pResult);
782f7141990Sdrh   return TCL_OK;
783f7141990Sdrh }
7849ac3fe97Sdrh 
7859ac3fe97Sdrh /*
786*d09414cdSdanielk1977 ** install_malloc_faultsim BOOLEAN
787*d09414cdSdanielk1977 */
788*d09414cdSdanielk1977 static int test_install_malloc_faultsim(
789*d09414cdSdanielk1977   void * clientData,
790*d09414cdSdanielk1977   Tcl_Interp *interp,
791*d09414cdSdanielk1977   int objc,
792*d09414cdSdanielk1977   Tcl_Obj *CONST objv[]
793*d09414cdSdanielk1977 ){
794*d09414cdSdanielk1977   int rc;
795*d09414cdSdanielk1977   int isInstall;
796*d09414cdSdanielk1977 
797*d09414cdSdanielk1977   if( objc!=2 ){
798*d09414cdSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
799*d09414cdSdanielk1977     return TCL_ERROR;
800*d09414cdSdanielk1977   }
801*d09414cdSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
802*d09414cdSdanielk1977     return TCL_ERROR;
803*d09414cdSdanielk1977   }
804*d09414cdSdanielk1977   rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, isInstall);
805*d09414cdSdanielk1977   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
806*d09414cdSdanielk1977   return TCL_OK;
807*d09414cdSdanielk1977 }
808*d09414cdSdanielk1977 
809*d09414cdSdanielk1977 /*
8102f999a67Sdrh ** Register commands with the TCL interpreter.
8112f999a67Sdrh */
8122f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){
8132f999a67Sdrh   static struct {
8142f999a67Sdrh      char *zName;
8152f999a67Sdrh      Tcl_ObjCmdProc *xProc;
8162f999a67Sdrh   } aObjCmd[] = {
8172f999a67Sdrh      { "sqlite3_malloc",             test_malloc                   },
8182f999a67Sdrh      { "sqlite3_realloc",            test_realloc                  },
8192f999a67Sdrh      { "sqlite3_free",               test_free                     },
8209c7a60dfSdrh      { "memset",                     test_memset                   },
8219c7a60dfSdrh      { "memget",                     test_memget                   },
8222f999a67Sdrh      { "sqlite3_memory_used",        test_memory_used              },
8232f999a67Sdrh      { "sqlite3_memory_highwater",   test_memory_highwater         },
8242f999a67Sdrh      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       },
8252f999a67Sdrh      { "sqlite3_memdebug_dump",      test_memdebug_dump            },
8260e6f1546Sdrh      { "sqlite3_memdebug_fail",      test_memdebug_fail            },
827cd03724cSdanielk1977      { "sqlite3_memdebug_pending",   test_memdebug_pending         },
8284a50aac5Sdrh      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        },
829a7a8e14bSdanielk1977      { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
8306f332c18Sdanielk1977      { "sqlite3_memdebug_log",       test_memdebug_log             },
8319ac3fe97Sdrh      { "sqlite3_config_scratch",     test_config_scratch           },
8329ac3fe97Sdrh      { "sqlite3_config_pagecache",   test_config_pagecache         },
833f7141990Sdrh      { "sqlite3_status",             test_status                   },
834*d09414cdSdanielk1977 
835*d09414cdSdanielk1977      { "install_malloc_faultsim",    test_install_malloc_faultsim  },
8362f999a67Sdrh   };
8372f999a67Sdrh   int i;
8382f999a67Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
8392f999a67Sdrh     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
8402f999a67Sdrh   }
8412f999a67Sdrh   return TCL_OK;
8422f999a67Sdrh }
843