xref: /sqlite-3.40.0/src/test_malloc.c (revision 2f999a67)
1*2f999a67Sdrh /*
2*2f999a67Sdrh ** 2007 August 15
3*2f999a67Sdrh **
4*2f999a67Sdrh ** The author disclaims copyright to this source code.  In place of
5*2f999a67Sdrh ** a legal notice, here is a blessing:
6*2f999a67Sdrh **
7*2f999a67Sdrh **    May you do good and not evil.
8*2f999a67Sdrh **    May you find forgiveness for yourself and forgive others.
9*2f999a67Sdrh **    May you share freely, never taking more than you give.
10*2f999a67Sdrh **
11*2f999a67Sdrh *************************************************************************
12*2f999a67Sdrh **
13*2f999a67Sdrh ** This file contains code used to implement test interfaces to the
14*2f999a67Sdrh ** memory allocation subsystem.
15*2f999a67Sdrh **
16*2f999a67Sdrh ** $Id: test_malloc.c,v 1.1 2007/08/15 19:16:43 drh Exp $
17*2f999a67Sdrh */
18*2f999a67Sdrh #include "sqliteInt.h"
19*2f999a67Sdrh #include "tcl.h"
20*2f999a67Sdrh #include <stdlib.h>
21*2f999a67Sdrh #include <string.h>
22*2f999a67Sdrh #include <assert.h>
23*2f999a67Sdrh 
24*2f999a67Sdrh /*
25*2f999a67Sdrh ** Transform pointers to text and back again
26*2f999a67Sdrh */
27*2f999a67Sdrh static void pointerToText(void *p, char *z){
28*2f999a67Sdrh   static const char zHex[] = "0123456789abcdef";
29*2f999a67Sdrh   int i, k;
30*2f999a67Sdrh   sqlite3_uint64 n = (sqlite3_uint64)p;
31*2f999a67Sdrh   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
32*2f999a67Sdrh     z[k] = zHex[n&0xf];
33*2f999a67Sdrh     n >>= 4;
34*2f999a67Sdrh   }
35*2f999a67Sdrh   z[sizeof(p)*2] = 0;
36*2f999a67Sdrh }
37*2f999a67Sdrh static int hexToInt(int h){
38*2f999a67Sdrh   if( h>='0' && h<='9' ){
39*2f999a67Sdrh     return h - '0';
40*2f999a67Sdrh   }else if( h>='a' && h<='f' ){
41*2f999a67Sdrh     return h - 'a' + 10;
42*2f999a67Sdrh   }else{
43*2f999a67Sdrh     return -1;
44*2f999a67Sdrh   }
45*2f999a67Sdrh }
46*2f999a67Sdrh static int textToPointer(const char *z, void **pp){
47*2f999a67Sdrh   sqlite3_uint64 n = 0;
48*2f999a67Sdrh   int i;
49*2f999a67Sdrh   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
50*2f999a67Sdrh     int v;
51*2f999a67Sdrh     v = hexToInt(*z++);
52*2f999a67Sdrh     if( v<0 ) return TCL_ERROR;
53*2f999a67Sdrh     n = n*16 + v;
54*2f999a67Sdrh   }
55*2f999a67Sdrh   if( *z!=0 ) return TCL_ERROR;
56*2f999a67Sdrh   *pp = (void*)n;
57*2f999a67Sdrh   return TCL_OK;
58*2f999a67Sdrh }
59*2f999a67Sdrh 
60*2f999a67Sdrh /*
61*2f999a67Sdrh ** Usage:    sqlite3_malloc  NBYTES
62*2f999a67Sdrh **
63*2f999a67Sdrh ** Raw test interface for sqlite3_malloc().
64*2f999a67Sdrh */
65*2f999a67Sdrh static int test_malloc(
66*2f999a67Sdrh   void * clientData,
67*2f999a67Sdrh   Tcl_Interp *interp,
68*2f999a67Sdrh   int objc,
69*2f999a67Sdrh   Tcl_Obj *CONST objv[]
70*2f999a67Sdrh ){
71*2f999a67Sdrh   int nByte;
72*2f999a67Sdrh   void *p;
73*2f999a67Sdrh   char zOut[100];
74*2f999a67Sdrh   if( objc!=2 ){
75*2f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
76*2f999a67Sdrh     return TCL_ERROR;
77*2f999a67Sdrh   }
78*2f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
79*2f999a67Sdrh   p = sqlite3_malloc((unsigned)nByte);
80*2f999a67Sdrh   pointerToText(p, zOut);
81*2f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
82*2f999a67Sdrh   return TCL_OK;
83*2f999a67Sdrh }
84*2f999a67Sdrh 
85*2f999a67Sdrh /*
86*2f999a67Sdrh ** Usage:    sqlite3_realloc  PRIOR  NBYTES
87*2f999a67Sdrh **
88*2f999a67Sdrh ** Raw test interface for sqlite3_realloc().
89*2f999a67Sdrh */
90*2f999a67Sdrh static int test_realloc(
91*2f999a67Sdrh   void * clientData,
92*2f999a67Sdrh   Tcl_Interp *interp,
93*2f999a67Sdrh   int objc,
94*2f999a67Sdrh   Tcl_Obj *CONST objv[]
95*2f999a67Sdrh ){
96*2f999a67Sdrh   int nByte;
97*2f999a67Sdrh   void *pPrior, *p;
98*2f999a67Sdrh   char zOut[100];
99*2f999a67Sdrh   if( objc!=3 ){
100*2f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
101*2f999a67Sdrh     return TCL_ERROR;
102*2f999a67Sdrh   }
103*2f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
104*2f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
105*2f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
106*2f999a67Sdrh     return TCL_ERROR;
107*2f999a67Sdrh   }
108*2f999a67Sdrh   p = sqlite3_realloc(pPrior, (unsigned)nByte);
109*2f999a67Sdrh   pointerToText(p, zOut);
110*2f999a67Sdrh   Tcl_AppendResult(interp, zOut, NULL);
111*2f999a67Sdrh   return TCL_OK;
112*2f999a67Sdrh }
113*2f999a67Sdrh 
114*2f999a67Sdrh 
115*2f999a67Sdrh /*
116*2f999a67Sdrh ** Usage:    sqlite3_free  PRIOR
117*2f999a67Sdrh **
118*2f999a67Sdrh ** Raw test interface for sqlite3_free().
119*2f999a67Sdrh */
120*2f999a67Sdrh static int test_free(
121*2f999a67Sdrh   void * clientData,
122*2f999a67Sdrh   Tcl_Interp *interp,
123*2f999a67Sdrh   int objc,
124*2f999a67Sdrh   Tcl_Obj *CONST objv[]
125*2f999a67Sdrh ){
126*2f999a67Sdrh   void *pPrior;
127*2f999a67Sdrh   if( objc!=2 ){
128*2f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
129*2f999a67Sdrh     return TCL_ERROR;
130*2f999a67Sdrh   }
131*2f999a67Sdrh   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
132*2f999a67Sdrh     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
133*2f999a67Sdrh     return TCL_ERROR;
134*2f999a67Sdrh   }
135*2f999a67Sdrh   sqlite3_free(pPrior);
136*2f999a67Sdrh   return TCL_OK;
137*2f999a67Sdrh }
138*2f999a67Sdrh 
139*2f999a67Sdrh /*
140*2f999a67Sdrh ** Usage:    sqlite3_memory_used
141*2f999a67Sdrh **
142*2f999a67Sdrh ** Raw test interface for sqlite3_memory_used().
143*2f999a67Sdrh */
144*2f999a67Sdrh static int test_memory_used(
145*2f999a67Sdrh   void * clientData,
146*2f999a67Sdrh   Tcl_Interp *interp,
147*2f999a67Sdrh   int objc,
148*2f999a67Sdrh   Tcl_Obj *CONST objv[]
149*2f999a67Sdrh ){
150*2f999a67Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
151*2f999a67Sdrh   return TCL_OK;
152*2f999a67Sdrh }
153*2f999a67Sdrh 
154*2f999a67Sdrh /*
155*2f999a67Sdrh ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
156*2f999a67Sdrh **
157*2f999a67Sdrh ** Raw test interface for sqlite3_memory_highwater().
158*2f999a67Sdrh */
159*2f999a67Sdrh static int test_memory_highwater(
160*2f999a67Sdrh   void * clientData,
161*2f999a67Sdrh   Tcl_Interp *interp,
162*2f999a67Sdrh   int objc,
163*2f999a67Sdrh   Tcl_Obj *CONST objv[]
164*2f999a67Sdrh ){
165*2f999a67Sdrh   int resetFlag = 0;
166*2f999a67Sdrh   if( objc!=1 && objc!=2 ){
167*2f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
168*2f999a67Sdrh     return TCL_ERROR;
169*2f999a67Sdrh   }
170*2f999a67Sdrh   if( objc==2 ){
171*2f999a67Sdrh     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
172*2f999a67Sdrh   }
173*2f999a67Sdrh   Tcl_SetObjResult(interp,
174*2f999a67Sdrh      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
175*2f999a67Sdrh   return TCL_OK;
176*2f999a67Sdrh }
177*2f999a67Sdrh 
178*2f999a67Sdrh /*
179*2f999a67Sdrh ** Usage:    sqlite3_memdebug_backtrace DEPTH
180*2f999a67Sdrh **
181*2f999a67Sdrh ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
182*2f999a67Sdrh ** then this routine is a no-op.
183*2f999a67Sdrh */
184*2f999a67Sdrh static int test_memdebug_backtrace(
185*2f999a67Sdrh   void * clientData,
186*2f999a67Sdrh   Tcl_Interp *interp,
187*2f999a67Sdrh   int objc,
188*2f999a67Sdrh   Tcl_Obj *CONST objv[]
189*2f999a67Sdrh ){
190*2f999a67Sdrh   int depth;
191*2f999a67Sdrh   if( objc!=2 ){
192*2f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
193*2f999a67Sdrh     return TCL_ERROR;
194*2f999a67Sdrh   }
195*2f999a67Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
196*2f999a67Sdrh #ifdef SQLITE_MEMDEBUG
197*2f999a67Sdrh   {
198*2f999a67Sdrh     extern void sqlite3_memdebug_backtrace(int);
199*2f999a67Sdrh     sqlite3_memdebug_backtrace(depth);
200*2f999a67Sdrh   }
201*2f999a67Sdrh #endif
202*2f999a67Sdrh   return TCL_OK;
203*2f999a67Sdrh }
204*2f999a67Sdrh 
205*2f999a67Sdrh /*
206*2f999a67Sdrh ** Usage:    sqlite3_memdebug_dump  FILENAME
207*2f999a67Sdrh **
208*2f999a67Sdrh ** Write a summary of unfreed memory to FILENAME.
209*2f999a67Sdrh */
210*2f999a67Sdrh static int test_memdebug_dump(
211*2f999a67Sdrh   void * clientData,
212*2f999a67Sdrh   Tcl_Interp *interp,
213*2f999a67Sdrh   int objc,
214*2f999a67Sdrh   Tcl_Obj *CONST objv[]
215*2f999a67Sdrh ){
216*2f999a67Sdrh   if( objc!=2 ){
217*2f999a67Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
218*2f999a67Sdrh     return TCL_ERROR;
219*2f999a67Sdrh   }
220*2f999a67Sdrh #ifdef SQLITE_MEMDEBUG
221*2f999a67Sdrh   {
222*2f999a67Sdrh     extern void sqlite3_memdebug_dump(const char*);
223*2f999a67Sdrh     sqlite3_memdebug_dump(Tcl_GetString(objv[1]));
224*2f999a67Sdrh   }
225*2f999a67Sdrh #endif
226*2f999a67Sdrh   return TCL_OK;
227*2f999a67Sdrh }
228*2f999a67Sdrh 
229*2f999a67Sdrh 
230*2f999a67Sdrh /*
231*2f999a67Sdrh ** Register commands with the TCL interpreter.
232*2f999a67Sdrh */
233*2f999a67Sdrh int Sqlitetest_malloc_Init(Tcl_Interp *interp){
234*2f999a67Sdrh   static struct {
235*2f999a67Sdrh      char *zName;
236*2f999a67Sdrh      Tcl_ObjCmdProc *xProc;
237*2f999a67Sdrh   } aObjCmd[] = {
238*2f999a67Sdrh      { "sqlite3_malloc",             test_malloc                   },
239*2f999a67Sdrh      { "sqlite3_realloc",            test_realloc                  },
240*2f999a67Sdrh      { "sqlite3_free",               test_free                     },
241*2f999a67Sdrh      { "sqlite3_memory_used",        test_memory_used              },
242*2f999a67Sdrh      { "sqlite3_memory_highwater",   test_memory_highwater         },
243*2f999a67Sdrh      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       },
244*2f999a67Sdrh      { "sqlite3_memdebug_dump",      test_memdebug_dump            },
245*2f999a67Sdrh   };
246*2f999a67Sdrh   int i;
247*2f999a67Sdrh   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
248*2f999a67Sdrh     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
249*2f999a67Sdrh   }
250*2f999a67Sdrh   return TCL_OK;
251*2f999a67Sdrh }
252