blob: d09f3e8993b49285a333920a10f80259af91df1f [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**
drh153c62c2007-08-24 03:51:33 +000016** $Id: test_malloc.c,v 1.5 2007/08/24 03:51:34 drh 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/*
drhed138fb2007-08-22 22:04:37 +0000248** Usage: sqlite3_memdebug_fail COUNTER ?REPEAT?
drh0e6f1542007-08-15 20:41:28 +0000249**
250** Arrange for a simulated malloc() failure after COUNTER successes.
251** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is
252** 0 then only a single failure occurs.
253**
254** Each call to this routine overrides the prior counter value.
255** This routine returns the number of simulated failures that have
256** happened since the previous call to this routine.
257**
258** To disable simulated failures, use a COUNTER of -1.
259*/
260static int test_memdebug_fail(
261 void * clientData,
262 Tcl_Interp *interp,
263 int objc,
264 Tcl_Obj *CONST objv[]
265){
266 int iFail;
267 int iRepeat;
268 int nFail = 0;
drhed138fb2007-08-22 22:04:37 +0000269 if( objc!=3 && objc!=2 ){
270 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?REPEAT?");
drh0e6f1542007-08-15 20:41:28 +0000271 return TCL_ERROR;
272 }
273 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
drhed138fb2007-08-22 22:04:37 +0000274 if( objc==3 ){
275 if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR;
276 }else{
277 iRepeat = -1;
278 }
drh0e6f1542007-08-15 20:41:28 +0000279#ifdef SQLITE_MEMDEBUG
280 {
281 extern int sqlite3_memdebug_fail(int,int);
282 nFail = sqlite3_memdebug_fail(iFail, iRepeat);
283 }
284#endif
285 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
286 return TCL_OK;
287}
288
289
290/*
drh4a50aac2007-08-23 02:47:53 +0000291** Usage: sqlite3_memdebug_settitle TITLE
292**
293** Set a title string stored with each allocation. The TITLE is
294** typically the name of the test that was running when the
295** allocation occurred. The TITLE is stored with the allocation
296** and can be used to figure out which tests are leaking memory.
297**
298** Each title overwrite the previous.
299*/
300static int test_memdebug_settitle(
301 void * clientData,
302 Tcl_Interp *interp,
303 int objc,
304 Tcl_Obj *CONST objv[]
305){
306 const char *zTitle;
307 if( objc!=2 ){
308 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
309 return TCL_ERROR;
310 }
311 zTitle = Tcl_GetString(objv[1]);
312#ifdef SQLITE_MEMDEBUG
313 {
314 extern int sqlite3_memdebug_settitle(const char*);
315 sqlite3_memdebug_settitle(zTitle);
316 }
317#endif
318 return TCL_OK;
319}
320
321
322/*
drh2f999a62007-08-15 19:16:43 +0000323** Register commands with the TCL interpreter.
324*/
325int Sqlitetest_malloc_Init(Tcl_Interp *interp){
326 static struct {
327 char *zName;
328 Tcl_ObjCmdProc *xProc;
329 } aObjCmd[] = {
330 { "sqlite3_malloc", test_malloc },
331 { "sqlite3_realloc", test_realloc },
332 { "sqlite3_free", test_free },
333 { "sqlite3_memory_used", test_memory_used },
334 { "sqlite3_memory_highwater", test_memory_highwater },
335 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace },
336 { "sqlite3_memdebug_dump", test_memdebug_dump },
drh0e6f1542007-08-15 20:41:28 +0000337 { "sqlite3_memdebug_fail", test_memdebug_fail },
drh4a50aac2007-08-23 02:47:53 +0000338 { "sqlite3_memdebug_settitle", test_memdebug_settitle },
drh2f999a62007-08-15 19:16:43 +0000339 };
340 int i;
341 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
342 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
343 }
344 return TCL_OK;
345}