xref: /sqlite-3.40.0/src/test_malloc.c (revision 999cc5d7)
1 /*
2 ** 2007 August 15
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** This file contains code used to implement test interfaces to the
14 ** memory allocation subsystem.
15 **
16 ** $Id: test_malloc.c,v 1.7 2007/08/30 15:46:07 danielk1977 Exp $
17 */
18 #include "sqliteInt.h"
19 #include "tcl.h"
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 
24 /*
25 ** Transform pointers to text and back again
26 */
27 static void pointerToText(void *p, char *z){
28   static const char zHex[] = "0123456789abcdef";
29   int i, k;
30   unsigned int u;
31   sqlite3_uint64 n;
32   if( sizeof(n)==sizeof(p) ){
33     memcpy(&n, &p, sizeof(p));
34   }else if( sizeof(u)==sizeof(p) ){
35     memcpy(&u, &p, sizeof(u));
36     n = u;
37   }else{
38     assert( 0 );
39   }
40   for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
41     z[k] = zHex[n&0xf];
42     n >>= 4;
43   }
44   z[sizeof(p)*2] = 0;
45 }
46 static int hexToInt(int h){
47   if( h>='0' && h<='9' ){
48     return h - '0';
49   }else if( h>='a' && h<='f' ){
50     return h - 'a' + 10;
51   }else{
52     return -1;
53   }
54 }
55 static int textToPointer(const char *z, void **pp){
56   sqlite3_uint64 n = 0;
57   int i;
58   unsigned int u;
59   for(i=0; i<sizeof(void*)*2 && z[0]; i++){
60     int v;
61     v = hexToInt(*z++);
62     if( v<0 ) return TCL_ERROR;
63     n = n*16 + v;
64   }
65   if( *z!=0 ) return TCL_ERROR;
66   if( sizeof(n)==sizeof(*pp) ){
67     memcpy(pp, &n, sizeof(n));
68   }else if( sizeof(u)==sizeof(*pp) ){
69     u = (unsigned int)n;
70     memcpy(pp, &u, sizeof(u));
71   }else{
72     assert( 0 );
73   }
74   return TCL_OK;
75 }
76 
77 /*
78 ** Usage:    sqlite3_malloc  NBYTES
79 **
80 ** Raw test interface for sqlite3_malloc().
81 */
82 static int test_malloc(
83   void * clientData,
84   Tcl_Interp *interp,
85   int objc,
86   Tcl_Obj *CONST objv[]
87 ){
88   int nByte;
89   void *p;
90   char zOut[100];
91   if( objc!=2 ){
92     Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
93     return TCL_ERROR;
94   }
95   if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
96   p = sqlite3_malloc((unsigned)nByte);
97   pointerToText(p, zOut);
98   Tcl_AppendResult(interp, zOut, NULL);
99   return TCL_OK;
100 }
101 
102 /*
103 ** Usage:    sqlite3_realloc  PRIOR  NBYTES
104 **
105 ** Raw test interface for sqlite3_realloc().
106 */
107 static int test_realloc(
108   void * clientData,
109   Tcl_Interp *interp,
110   int objc,
111   Tcl_Obj *CONST objv[]
112 ){
113   int nByte;
114   void *pPrior, *p;
115   char zOut[100];
116   if( objc!=3 ){
117     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
118     return TCL_ERROR;
119   }
120   if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
121   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
122     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
123     return TCL_ERROR;
124   }
125   p = sqlite3_realloc(pPrior, (unsigned)nByte);
126   pointerToText(p, zOut);
127   Tcl_AppendResult(interp, zOut, NULL);
128   return TCL_OK;
129 }
130 
131 
132 /*
133 ** Usage:    sqlite3_free  PRIOR
134 **
135 ** Raw test interface for sqlite3_free().
136 */
137 static int test_free(
138   void * clientData,
139   Tcl_Interp *interp,
140   int objc,
141   Tcl_Obj *CONST objv[]
142 ){
143   void *pPrior;
144   if( objc!=2 ){
145     Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
146     return TCL_ERROR;
147   }
148   if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
149     Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
150     return TCL_ERROR;
151   }
152   sqlite3_free(pPrior);
153   return TCL_OK;
154 }
155 
156 /*
157 ** Usage:    sqlite3_memory_used
158 **
159 ** Raw test interface for sqlite3_memory_used().
160 */
161 static int test_memory_used(
162   void * clientData,
163   Tcl_Interp *interp,
164   int objc,
165   Tcl_Obj *CONST objv[]
166 ){
167   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
168   return TCL_OK;
169 }
170 
171 /*
172 ** Usage:    sqlite3_memory_highwater ?RESETFLAG?
173 **
174 ** Raw test interface for sqlite3_memory_highwater().
175 */
176 static int test_memory_highwater(
177   void * clientData,
178   Tcl_Interp *interp,
179   int objc,
180   Tcl_Obj *CONST objv[]
181 ){
182   int resetFlag = 0;
183   if( objc!=1 && objc!=2 ){
184     Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
185     return TCL_ERROR;
186   }
187   if( objc==2 ){
188     if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
189   }
190   Tcl_SetObjResult(interp,
191      Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
192   return TCL_OK;
193 }
194 
195 /*
196 ** Usage:    sqlite3_memdebug_backtrace DEPTH
197 **
198 ** Set the depth of backtracing.  If SQLITE_MEMDEBUG is not defined
199 ** then this routine is a no-op.
200 */
201 static int test_memdebug_backtrace(
202   void * clientData,
203   Tcl_Interp *interp,
204   int objc,
205   Tcl_Obj *CONST objv[]
206 ){
207   int depth;
208   if( objc!=2 ){
209     Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
210     return TCL_ERROR;
211   }
212   if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
213 #ifdef SQLITE_MEMDEBUG
214   {
215     extern void sqlite3_memdebug_backtrace(int);
216     sqlite3_memdebug_backtrace(depth);
217   }
218 #endif
219   return TCL_OK;
220 }
221 
222 /*
223 ** Usage:    sqlite3_memdebug_dump  FILENAME
224 **
225 ** Write a summary of unfreed memory to FILENAME.
226 */
227 static int test_memdebug_dump(
228   void * clientData,
229   Tcl_Interp *interp,
230   int objc,
231   Tcl_Obj *CONST objv[]
232 ){
233   if( objc!=2 ){
234     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
235     return TCL_ERROR;
236   }
237 #ifdef SQLITE_MEMDEBUG
238   {
239     extern void sqlite3_memdebug_dump(const char*);
240     sqlite3_memdebug_dump(Tcl_GetString(objv[1]));
241   }
242 #endif
243   return TCL_OK;
244 }
245 
246 
247 /*
248 ** Usage:    sqlite3_memdebug_fail  COUNTER  ?OPTIONS?
249 **
250 ** where options are:
251 **
252 **     -repeat    <boolean>
253 **     -benigncnt <varname>
254 **
255 ** Arrange for a simulated malloc() failure after COUNTER successes.
256 ** If REPEAT is 1 then all subsequent malloc()s fail.   If REPEAT is
257 ** 0 then only a single failure occurs.
258 **
259 ** Each call to this routine overrides the prior counter value.
260 ** This routine returns the number of simulated failures that have
261 ** happened since the previous call to this routine.
262 **
263 ** To disable simulated failures, use a COUNTER of -1.
264 */
265 static int test_memdebug_fail(
266   void * clientData,
267   Tcl_Interp *interp,
268   int objc,
269   Tcl_Obj *CONST objv[]
270 ){
271   int ii;
272   int iFail;
273   int iRepeat = -1;
274   int iBenignCnt;
275   Tcl_Obj *pBenignCnt = 0;
276 
277   int nFail = 0;
278 
279   if( objc<2 ){
280     Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
281     return TCL_ERROR;
282   }
283   if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
284 
285   for(ii=2; ii<objc; ii+=2){
286     int nOption;
287     char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
288     char *zErr = 0;
289 
290     if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
291       if( ii==(objc-1) ){
292         zErr = "option requires an argument: ";
293       }else{
294         if( Tcl_GetIntFromObj(interp, objv[ii+1], &iRepeat) ){
295           return TCL_ERROR;
296         }
297       }
298     }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
299       if( ii==(objc-1) ){
300         zErr = "option requires an argument: ";
301       }else{
302         pBenignCnt = objv[ii+1];
303       }
304     }else{
305       zErr = "unknown option: ";
306     }
307 
308     if( zErr ){
309       Tcl_AppendResult(interp, zErr, zOption, 0);
310       return TCL_ERROR;
311     }
312   }
313 
314 #ifdef SQLITE_MEMDEBUG
315   {
316     extern int sqlite3_memdebug_fail(int,int,int*);
317     nFail = sqlite3_memdebug_fail(iFail, iRepeat, &iBenignCnt);
318     if( pBenignCnt ){
319       Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(iBenignCnt), 0);
320     }
321   }
322 #endif
323   Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
324   return TCL_OK;
325 }
326 
327 /*
328 ** Usage:    sqlite3_memdebug_pending
329 **
330 ** Return the number of malloc() calls that will succeed before a
331 ** simulated failure occurs. A negative return value indicates that
332 ** no malloc() failure is scheduled.
333 */
334 static int test_memdebug_pending(
335   void * clientData,
336   Tcl_Interp *interp,
337   int objc,
338   Tcl_Obj *CONST objv[]
339 ){
340   if( objc!=1 ){
341     Tcl_WrongNumArgs(interp, 1, objv, "");
342     return TCL_ERROR;
343   }
344 
345 #ifdef SQLITE_MEMDEBUG
346   {
347     extern int sqlite3_memdebug_pending();
348     Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_pending()));
349   }
350 #endif
351   return TCL_OK;
352 }
353 
354 
355 /*
356 ** Usage:    sqlite3_memdebug_settitle TITLE
357 **
358 ** Set a title string stored with each allocation.  The TITLE is
359 ** typically the name of the test that was running when the
360 ** allocation occurred.  The TITLE is stored with the allocation
361 ** and can be used to figure out which tests are leaking memory.
362 **
363 ** Each title overwrite the previous.
364 */
365 static int test_memdebug_settitle(
366   void * clientData,
367   Tcl_Interp *interp,
368   int objc,
369   Tcl_Obj *CONST objv[]
370 ){
371   const char *zTitle;
372   if( objc!=2 ){
373     Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
374     return TCL_ERROR;
375   }
376   zTitle = Tcl_GetString(objv[1]);
377 #ifdef SQLITE_MEMDEBUG
378   {
379     extern int sqlite3_memdebug_settitle(const char*);
380     sqlite3_memdebug_settitle(zTitle);
381   }
382 #endif
383   return TCL_OK;
384 }
385 
386 
387 /*
388 ** Register commands with the TCL interpreter.
389 */
390 int Sqlitetest_malloc_Init(Tcl_Interp *interp){
391   static struct {
392      char *zName;
393      Tcl_ObjCmdProc *xProc;
394   } aObjCmd[] = {
395      { "sqlite3_malloc",             test_malloc                   },
396      { "sqlite3_realloc",            test_realloc                  },
397      { "sqlite3_free",               test_free                     },
398      { "sqlite3_memory_used",        test_memory_used              },
399      { "sqlite3_memory_highwater",   test_memory_highwater         },
400      { "sqlite3_memdebug_backtrace", test_memdebug_backtrace       },
401      { "sqlite3_memdebug_dump",      test_memdebug_dump            },
402      { "sqlite3_memdebug_fail",      test_memdebug_fail            },
403      { "sqlite3_memdebug_pending",   test_memdebug_pending         },
404      { "sqlite3_memdebug_settitle",  test_memdebug_settitle        },
405   };
406   int i;
407   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
408     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
409   }
410   return TCL_OK;
411 }
412