blob: a0b03c37028e37e3ac4d60d6850cf4c427069d27 [file] [log] [blame]
drh2f999a62007-08-15 19:16:43 +00001/*
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**
danielk1977a1644fd2007-08-29 12:31:25 +000016** $Id: test_malloc.c,v 1.6 2007/08/29 12:31:28 danielk1977 Exp $
drh2f999a62007-08-15 19:16:43 +000017*/
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*/
27static void pointerToText(void *p, char *z){
28 static const char zHex[] = "0123456789abcdef";
29 int i, k;
drh4a50aac2007-08-23 02:47:53 +000030 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 }
drh2f999a62007-08-15 19:16:43 +000040 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}
46static 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}
55static int textToPointer(const char *z, void **pp){
56 sqlite3_uint64 n = 0;
57 int i;
drh4a50aac2007-08-23 02:47:53 +000058 unsigned int u;
drh2f999a62007-08-15 19:16:43 +000059 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;
drh4a50aac2007-08-23 02:47:53 +000066 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 }
drh2f999a62007-08-15 19:16:43 +000074 return TCL_OK;
75}
76
77/*
78** Usage: sqlite3_malloc NBYTES
79**
80** Raw test interface for sqlite3_malloc().
81*/
82static 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*/
107static 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*/
137static 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*/
161static 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*/
176static 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*/
201static 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*/
227static 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/*
danielk1977a1644fd2007-08-29 12:31:25 +0000248** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
249**
250** where options are:
251**
252** -repeat <boolean>
253** -benigncnt <varname>
drh0e6f1542007-08-15 20:41:28 +0000254**
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*/
265static int test_memdebug_fail(
266 void * clientData,
267 Tcl_Interp *interp,
268 int objc,
269 Tcl_Obj *CONST objv[]
270){
danielk1977a1644fd2007-08-29 12:31:25 +0000271 int ii;
drh0e6f1542007-08-15 20:41:28 +0000272 int iFail;
danielk1977a1644fd2007-08-29 12:31:25 +0000273 int iRepeat = -1;
274 int iBenignCnt;
275 Tcl_Obj *pBenignCnt = 0;
276
drh0e6f1542007-08-15 20:41:28 +0000277 int nFail = 0;
danielk1977a1644fd2007-08-29 12:31:25 +0000278
279 if( objc<2 ){
280 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
drh0e6f1542007-08-15 20:41:28 +0000281 return TCL_ERROR;
282 }
283 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +0000284
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 }
drhed138fb2007-08-22 22:04:37 +0000312 }
danielk1977a1644fd2007-08-29 12:31:25 +0000313
drh0e6f1542007-08-15 20:41:28 +0000314#ifdef SQLITE_MEMDEBUG
315 {
danielk1977a1644fd2007-08-29 12:31:25 +0000316 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 }
drh0e6f1542007-08-15 20:41:28 +0000321 }
322#endif
323 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
324 return TCL_OK;
325}
326
327
328/*
drh4a50aac2007-08-23 02:47:53 +0000329** Usage: sqlite3_memdebug_settitle TITLE
330**
331** Set a title string stored with each allocation. The TITLE is
332** typically the name of the test that was running when the
333** allocation occurred. The TITLE is stored with the allocation
334** and can be used to figure out which tests are leaking memory.
335**
336** Each title overwrite the previous.
337*/
338static int test_memdebug_settitle(
339 void * clientData,
340 Tcl_Interp *interp,
341 int objc,
342 Tcl_Obj *CONST objv[]
343){
344 const char *zTitle;
345 if( objc!=2 ){
346 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
347 return TCL_ERROR;
348 }
349 zTitle = Tcl_GetString(objv[1]);
350#ifdef SQLITE_MEMDEBUG
351 {
352 extern int sqlite3_memdebug_settitle(const char*);
353 sqlite3_memdebug_settitle(zTitle);
354 }
355#endif
356 return TCL_OK;
357}
358
359
360/*
drh2f999a62007-08-15 19:16:43 +0000361** Register commands with the TCL interpreter.
362*/
363int Sqlitetest_malloc_Init(Tcl_Interp *interp){
364 static struct {
365 char *zName;
366 Tcl_ObjCmdProc *xProc;
367 } aObjCmd[] = {
368 { "sqlite3_malloc", test_malloc },
369 { "sqlite3_realloc", test_realloc },
370 { "sqlite3_free", test_free },
371 { "sqlite3_memory_used", test_memory_used },
372 { "sqlite3_memory_highwater", test_memory_highwater },
373 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace },
374 { "sqlite3_memdebug_dump", test_memdebug_dump },
drh0e6f1542007-08-15 20:41:28 +0000375 { "sqlite3_memdebug_fail", test_memdebug_fail },
drh4a50aac2007-08-23 02:47:53 +0000376 { "sqlite3_memdebug_settitle", test_memdebug_settitle },
drh2f999a62007-08-15 19:16:43 +0000377 };
378 int i;
379 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
380 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
381 }
382 return TCL_OK;
383}