xref: /sqlite-3.40.0/src/test_malloc.c (revision ed138fb3)
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*ed138fb3Sdrh ** $Id: test_malloc.c,v 1.3 2007/08/22 22:04:37 drh Exp $
172f999a67Sdrh */
182f999a67Sdrh #include "sqliteInt.h"
192f999a67Sdrh #include "tcl.h"
202f999a67Sdrh #include <stdlib.h>
212f999a67Sdrh #include <string.h>
222f999a67Sdrh #include <assert.h>
232f999a67Sdrh 
242f999a67Sdrh /*
252f999a67Sdrh ** Transform pointers to text and back again
262f999a67Sdrh */
272f999a67Sdrh static void pointerToText(void *p, char *z){
282f999a67Sdrh   static const char zHex[] = "0123456789abcdef";
292f999a67Sdrh   int i, k;
302f999a67Sdrh   sqlite3_uint64 n = (sqlite3_uint64)p;
312f999a67Sdrh   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
322f999a67Sdrh     z[k] = zHex[n&0xf];
332f999a67Sdrh     n >>= 4;
342f999a67Sdrh   }
352f999a67Sdrh   z[sizeof(p)*2] = 0;
362f999a67Sdrh }
372f999a67Sdrh static int hexToInt(int h){
382f999a67Sdrh   if( h>='0' && h<='9' ){
392f999a67Sdrh     return h - '0';
402f999a67Sdrh   }else if( h>='a' && h<='f' ){
412f999a67Sdrh     return h - 'a' + 10;
422f999a67Sdrh   }else{
432f999a67Sdrh     return -1;
442f999a67Sdrh   }
452f999a67Sdrh }
462f999a67Sdrh static int textToPointer(const char *z, void **pp){
472f999a67Sdrh   sqlite3_uint64 n = 0;
482f999a67Sdrh   int i;
492f999a67Sdrh   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
502f999a67Sdrh     int v;
512f999a67Sdrh     v = hexToInt(*z++);
522f999a67Sdrh     if( v<0 ) return TCL_ERROR;
532f999a67Sdrh     n = n*16 + v;
542f999a67Sdrh   }
552f999a67Sdrh   if( *z!=0 ) return TCL_ERROR;
562f999a67Sdrh   *pp = (void*)n;
572f999a67Sdrh   return TCL_OK;
582f999a67Sdrh }
592f999a67Sdrh 
602f999a67Sdrh /*
612f999a67Sdrh ** Usage:    sqlite3_malloc  NBYTES
622f999a67Sdrh **
632f999a67Sdrh ** Raw test interface for sqlite3_malloc().
642f999a67Sdrh */
652f999a67Sdrh static int test_malloc(
662f999a67Sdrh   void * clientData,
672f999a67Sdrh   Tcl_Interp *interp,
682f999a67Sdrh   int objc,
692f999a67Sdrh   Tcl_Obj *CONST objv[]
702f999a67Sdrh ){
712f999a67Sdrh   int nByte;
722f999a67Sdrh   void *p;
732f999a67Sdrh   char zOut[100];
742f999a67Sdrh   if( objc!=2 ){
752f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
762f999a67Sdrh     return TCL_ERROR;
772f999a67Sdrh   }
782f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
792f999a67Sdrh   p = sqlite3_malloc((unsigned)nByte);
802f999a67Sdrh   pointerToText(p, zOut);
812f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
822f999a67Sdrh   return TCL_OK;
832f999a67Sdrh }
842f999a67Sdrh 
852f999a67Sdrh /*
862f999a67Sdrh ** Usage:    sqlite3_realloc  PRIOR  NBYTES
872f999a67Sdrh **
882f999a67Sdrh ** Raw test interface for sqlite3_realloc().
892f999a67Sdrh */
902f999a67Sdrh static int test_realloc(
912f999a67Sdrh   void * clientData,
922f999a67Sdrh   Tcl_Interp *interp,
932f999a67Sdrh   int objc,
942f999a67Sdrh   Tcl_Obj *CONST objv[]
952f999a67Sdrh ){
962f999a67Sdrh   int nByte;
972f999a67Sdrh   void *pPrior, *p;
982f999a67Sdrh   char zOut[100];
992f999a67Sdrh   if( objc!=3 ){
1002f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
1012f999a67Sdrh     return TCL_ERROR;
1022f999a67Sdrh   }
1032f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
1042f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
1052f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
1062f999a67Sdrh     return TCL_ERROR;
1072f999a67Sdrh   }
1082f999a67Sdrh   p = sqlite3_realloc(pPrior, (unsigned)nByte);
1092f999a67Sdrh   pointerToText(p, zOut);
1102f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
1112f999a67Sdrh   return TCL_OK;
1122f999a67Sdrh }
1132f999a67Sdrh 
1142f999a67Sdrh 
1152f999a67Sdrh /*
1162f999a67Sdrh ** Usage:    sqlite3_free  PRIOR
1172f999a67Sdrh **
1182f999a67Sdrh ** Raw test interface for sqlite3_free().
1192f999a67Sdrh */
1202f999a67Sdrh static int test_free(
1212f999a67Sdrh   void * clientData,
1222f999a67Sdrh   Tcl_Interp *interp,
1232f999a67Sdrh   int objc,
1242f999a67Sdrh   Tcl_Obj *CONST objv[]
1252f999a67Sdrh ){
1262f999a67Sdrh   void *pPrior;
1272f999a67Sdrh   if( objc!=2 ){
1282f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
1292f999a67Sdrh     return TCL_ERROR;
1302f999a67Sdrh   }
1312f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
1322f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
1332f999a67Sdrh     return TCL_ERROR;
1342f999a67Sdrh   }
1352f999a67Sdrh   sqlite3_free(pPrior);
1362f999a67Sdrh   return TCL_OK;
1372f999a67Sdrh }
1382f999a67Sdrh 
1392f999a67Sdrh /*
1402f999a67Sdrh ** Usage:    sqlite3_memory_used
1412f999a67Sdrh **
1422f999a67Sdrh ** Raw test interface for sqlite3_memory_used().
1432f999a67Sdrh */
1442f999a67Sdrh static int test_memory_used(
1452f999a67Sdrh   void * clientData,
1462f999a67Sdrh   Tcl_Interp *interp,
1472f999a67Sdrh   int objc,
1482f999a67Sdrh   Tcl_Obj *CONST objv[]
1492f999a67Sdrh ){
1502f999a67Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
1512f999a67Sdrh   return TCL_OK;
1522f999a67Sdrh }
1532f999a67Sdrh 
1542f999a67Sdrh /*
1552f999a67Sdrh ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
1562f999a67Sdrh **
1572f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater().
1582f999a67Sdrh */
1592f999a67Sdrh static int test_memory_highwater(
1602f999a67Sdrh   void * clientData,
1612f999a67Sdrh   Tcl_Interp *interp,
1622f999a67Sdrh   int objc,
1632f999a67Sdrh   Tcl_Obj *CONST objv[]
1642f999a67Sdrh ){
1652f999a67Sdrh   int resetFlag = 0;
1662f999a67Sdrh   if( objc!=1 && objc!=2 ){
1672f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
1682f999a67Sdrh     return TCL_ERROR;
1692f999a67Sdrh   }
1702f999a67Sdrh   if( objc==2 ){
1712f999a67Sdrh     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
1722f999a67Sdrh   }
1732f999a67Sdrh   Tcl_SetObjResult(interp,
1742f999a67Sdrh      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
1752f999a67Sdrh   return TCL_OK;
1762f999a67Sdrh }
1772f999a67Sdrh 
1782f999a67Sdrh /*
1792f999a67Sdrh ** Usage:    sqlite3_memdebug_backtrace DEPTH
1802f999a67Sdrh **
1812f999a67Sdrh ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
1822f999a67Sdrh ** then this routine is a no-op.
1832f999a67Sdrh */
1842f999a67Sdrh static int test_memdebug_backtrace(
1852f999a67Sdrh   void * clientData,
1862f999a67Sdrh   Tcl_Interp *interp,
1872f999a67Sdrh   int objc,
1882f999a67Sdrh   Tcl_Obj *CONST objv[]
1892f999a67Sdrh ){
1902f999a67Sdrh   int depth;
1912f999a67Sdrh   if( objc!=2 ){
1922f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
1932f999a67Sdrh     return TCL_ERROR;
1942f999a67Sdrh   }
1952f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
1962f999a67Sdrh #ifdef SQLITE_MEMDEBUG
1972f999a67Sdrh   {
1982f999a67Sdrh     extern void sqlite3_memdebug_backtrace(int);
1992f999a67Sdrh     sqlite3_memdebug_backtrace(depth);
2002f999a67Sdrh   }
2012f999a67Sdrh #endif
2022f999a67Sdrh   return TCL_OK;
2032f999a67Sdrh }
2042f999a67Sdrh 
2052f999a67Sdrh /*
2062f999a67Sdrh ** Usage:    sqlite3_memdebug_dump  FILENAME
2072f999a67Sdrh **
2082f999a67Sdrh ** Write a summary of unfreed memory to FILENAME.
2092f999a67Sdrh */
2102f999a67Sdrh static int test_memdebug_dump(
2112f999a67Sdrh   void * clientData,
2122f999a67Sdrh   Tcl_Interp *interp,
2132f999a67Sdrh   int objc,
2142f999a67Sdrh   Tcl_Obj *CONST objv[]
2152f999a67Sdrh ){
2162f999a67Sdrh   if( objc!=2 ){
2172f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
2182f999a67Sdrh     return TCL_ERROR;
2192f999a67Sdrh   }
2202f999a67Sdrh #ifdef SQLITE_MEMDEBUG
2212f999a67Sdrh   {
2222f999a67Sdrh     extern void sqlite3_memdebug_dump(const char*);
2232f999a67Sdrh     sqlite3_memdebug_dump(Tcl_GetString(objv[1]));
2242f999a67Sdrh   }
2252f999a67Sdrh #endif
2262f999a67Sdrh   return TCL_OK;
2272f999a67Sdrh }
2282f999a67Sdrh 
2292f999a67Sdrh 
2302f999a67Sdrh /*
231*ed138fb3Sdrh ** Usage:    sqlite3_memdebug_fail  COUNTER  ?REPEAT?
2320e6f1546Sdrh **
2330e6f1546Sdrh ** Arrange for a simulated malloc() failure after COUNTER successes.
2340e6f1546Sdrh ** If REPEAT is 1 then all subsequent malloc()s fail.   If REPEAT is
2350e6f1546Sdrh ** 0 then only a single failure occurs.
2360e6f1546Sdrh **
2370e6f1546Sdrh ** Each call to this routine overrides the prior counter value.
2380e6f1546Sdrh ** This routine returns the number of simulated failures that have
2390e6f1546Sdrh ** happened since the previous call to this routine.
2400e6f1546Sdrh **
2410e6f1546Sdrh ** To disable simulated failures, use a COUNTER of -1.
2420e6f1546Sdrh */
2430e6f1546Sdrh static int test_memdebug_fail(
2440e6f1546Sdrh   void * clientData,
2450e6f1546Sdrh   Tcl_Interp *interp,
2460e6f1546Sdrh   int objc,
2470e6f1546Sdrh   Tcl_Obj *CONST objv[]
2480e6f1546Sdrh ){
2490e6f1546Sdrh   int iFail;
2500e6f1546Sdrh   int iRepeat;
2510e6f1546Sdrh   int nFail = 0;
252*ed138fb3Sdrh   if( objc!=3 && objc!=2 ){
253*ed138fb3Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?REPEAT?");
2540e6f1546Sdrh     return TCL_ERROR;
2550e6f1546Sdrh   }
2560e6f1546Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
257*ed138fb3Sdrh   if( objc==3 ){
2580e6f1546Sdrh     if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR;
259*ed138fb3Sdrh   }else{
260*ed138fb3Sdrh     iRepeat = -1;
261*ed138fb3Sdrh   }
2620e6f1546Sdrh #ifdef SQLITE_MEMDEBUG
2630e6f1546Sdrh   {
2640e6f1546Sdrh     extern int sqlite3_memdebug_fail(int,int);
2650e6f1546Sdrh     nFail = sqlite3_memdebug_fail(iFail, iRepeat);
2660e6f1546Sdrh   }
2670e6f1546Sdrh #endif
2680e6f1546Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
2690e6f1546Sdrh   return TCL_OK;
2700e6f1546Sdrh }
2710e6f1546Sdrh 
2720e6f1546Sdrh 
2730e6f1546Sdrh /*
274*ed138fb3Sdrh ** Usage:    sqlite3_memdebug_pending
275*ed138fb3Sdrh **
276*ed138fb3Sdrh ** Return the number of successful mallocs remaining before the
277*ed138fb3Sdrh ** next simulated failure.  Return -1 if no simulated failure is
278*ed138fb3Sdrh ** currently scheduled.
279*ed138fb3Sdrh */
280*ed138fb3Sdrh static int test_memdebug_pending(
281*ed138fb3Sdrh   void * clientData,
282*ed138fb3Sdrh   Tcl_Interp *interp,
283*ed138fb3Sdrh   int objc,
284*ed138fb3Sdrh   Tcl_Obj *CONST objv[]
285*ed138fb3Sdrh ){
286*ed138fb3Sdrh   extern int sqlite3_memdebug_pending(void);
287*ed138fb3Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_pending()));
288*ed138fb3Sdrh   return TCL_OK;
289*ed138fb3Sdrh }
290*ed138fb3Sdrh 
291*ed138fb3Sdrh 
292*ed138fb3Sdrh /*
2932f999a67Sdrh ** Register commands with the TCL interpreter.
2942f999a67Sdrh */
2952f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){
2962f999a67Sdrh   static struct {
2972f999a67Sdrh      char *zName;
2982f999a67Sdrh      Tcl_ObjCmdProc *xProc;
2992f999a67Sdrh   } aObjCmd[] = {
3002f999a67Sdrh      { "sqlite3_malloc",             test_malloc                   },
3012f999a67Sdrh      { "sqlite3_realloc",            test_realloc                  },
3022f999a67Sdrh      { "sqlite3_free",               test_free                     },
3032f999a67Sdrh      { "sqlite3_memory_used",        test_memory_used              },
3042f999a67Sdrh      { "sqlite3_memory_highwater",   test_memory_highwater         },
3052f999a67Sdrh      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       },
3062f999a67Sdrh      { "sqlite3_memdebug_dump",      test_memdebug_dump            },
3070e6f1546Sdrh      { "sqlite3_memdebug_fail",      test_memdebug_fail            },
308*ed138fb3Sdrh      { "sqlite3_memdebug_pending",   test_memdebug_pending         },
3092f999a67Sdrh   };
3102f999a67Sdrh   int i;
3112f999a67Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
3122f999a67Sdrh     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
3132f999a67Sdrh   }
3142f999a67Sdrh   return TCL_OK;
3152f999a67Sdrh }
316