blob: 3595a0651f6883ba12fe2a83c705a6b093c62df3 [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**
danielk1977cd3e8f72008-03-25 09:47:35 +000016** $Id: test_malloc.c,v 1.19 2008/03/25 09:47:35 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/*
drh9c7a60d2007-10-19 17:47:24 +0000157** These routines are in test_hexio.c
158*/
159int sqlite3TestHexToBin(const char *, int, char *);
160int sqlite3TestBinToHex(char*,int);
161
162/*
163** Usage: memset ADDRESS SIZE HEX
164**
165** Set a chunk of memory (obtained from malloc, probably) to a
166** specified hex pattern.
167*/
168static int test_memset(
169 void * clientData,
170 Tcl_Interp *interp,
171 int objc,
172 Tcl_Obj *CONST objv[]
173){
174 void *p;
175 int size, n, i;
176 char *zHex;
177 char *zOut;
178 char zBin[100];
179
180 if( objc!=4 ){
181 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
182 return TCL_ERROR;
183 }
184 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
185 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
186 return TCL_ERROR;
187 }
188 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
189 return TCL_ERROR;
190 }
191 if( size<=0 ){
192 Tcl_AppendResult(interp, "size must be positive", (char*)0);
193 return TCL_ERROR;
194 }
195 zHex = Tcl_GetStringFromObj(objv[3], &n);
196 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
197 n = sqlite3TestHexToBin(zHex, n, zBin);
198 if( n==0 ){
199 Tcl_AppendResult(interp, "no data", (char*)0);
200 return TCL_ERROR;
201 }
202 zOut = p;
203 for(i=0; i<size; i++){
204 zOut[i] = zBin[i%n];
205 }
206 return TCL_OK;
207}
208
209/*
210** Usage: memget ADDRESS SIZE
211**
212** Return memory as hexadecimal text.
213*/
214static int test_memget(
215 void * clientData,
216 Tcl_Interp *interp,
217 int objc,
218 Tcl_Obj *CONST objv[]
219){
220 void *p;
221 int size, n;
222 char *zBin;
223 char zHex[100];
224
225 if( objc!=3 ){
226 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
227 return TCL_ERROR;
228 }
229 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
230 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
231 return TCL_ERROR;
232 }
233 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
234 return TCL_ERROR;
235 }
236 if( size<=0 ){
237 Tcl_AppendResult(interp, "size must be positive", (char*)0);
238 return TCL_ERROR;
239 }
240 zBin = p;
241 while( size>0 ){
242 if( size>(sizeof(zHex)-1)/2 ){
243 n = (sizeof(zHex)-1)/2;
244 }else{
245 n = size;
246 }
247 memcpy(zHex, zBin, n);
248 zBin += n;
249 size -= n;
250 sqlite3TestBinToHex(zHex, n);
251 Tcl_AppendResult(interp, zHex, (char*)0);
252 }
253 return TCL_OK;
254}
255
256/*
drh2f999a62007-08-15 19:16:43 +0000257** Usage: sqlite3_memory_used
258**
259** Raw test interface for sqlite3_memory_used().
260*/
261static int test_memory_used(
262 void * clientData,
263 Tcl_Interp *interp,
264 int objc,
265 Tcl_Obj *CONST objv[]
266){
267 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
268 return TCL_OK;
269}
270
271/*
272** Usage: sqlite3_memory_highwater ?RESETFLAG?
273**
274** Raw test interface for sqlite3_memory_highwater().
275*/
276static int test_memory_highwater(
277 void * clientData,
278 Tcl_Interp *interp,
279 int objc,
280 Tcl_Obj *CONST objv[]
281){
282 int resetFlag = 0;
283 if( objc!=1 && objc!=2 ){
284 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
285 return TCL_ERROR;
286 }
287 if( objc==2 ){
288 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
289 }
290 Tcl_SetObjResult(interp,
291 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
292 return TCL_OK;
293}
294
295/*
296** Usage: sqlite3_memdebug_backtrace DEPTH
297**
298** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
299** then this routine is a no-op.
300*/
301static int test_memdebug_backtrace(
302 void * clientData,
303 Tcl_Interp *interp,
304 int objc,
305 Tcl_Obj *CONST objv[]
306){
307 int depth;
308 if( objc!=2 ){
309 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
310 return TCL_ERROR;
311 }
312 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
313#ifdef SQLITE_MEMDEBUG
314 {
drh49e4fd72008-02-19 15:15:15 +0000315 extern void sqlite3MemdebugBacktrace(int);
316 sqlite3MemdebugBacktrace(depth);
drh2f999a62007-08-15 19:16:43 +0000317 }
318#endif
319 return TCL_OK;
320}
321
322/*
323** Usage: sqlite3_memdebug_dump FILENAME
324**
325** Write a summary of unfreed memory to FILENAME.
326*/
327static int test_memdebug_dump(
328 void * clientData,
329 Tcl_Interp *interp,
330 int objc,
331 Tcl_Obj *CONST objv[]
332){
333 if( objc!=2 ){
334 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
335 return TCL_ERROR;
336 }
drh2d7636e2008-02-16 16:21:45 +0000337#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
338 || defined(SQLITE_POW2_MEMORY_SIZE)
drh2f999a62007-08-15 19:16:43 +0000339 {
drh49e4fd72008-02-19 15:15:15 +0000340 extern void sqlite3MemdebugDump(const char*);
341 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
drh2f999a62007-08-15 19:16:43 +0000342 }
343#endif
344 return TCL_OK;
345}
346
danielk1977a7a8e142008-02-13 18:25:27 +0000347/*
348** Usage: sqlite3_memdebug_malloc_count
349**
350** Return the total number of times malloc() has been called.
351*/
352static int test_memdebug_malloc_count(
353 void * clientData,
354 Tcl_Interp *interp,
355 int objc,
356 Tcl_Obj *CONST objv[]
357){
358 int nMalloc = -1;
359 if( objc!=1 ){
360 Tcl_WrongNumArgs(interp, 1, objv, "");
361 return TCL_ERROR;
362 }
363#if defined(SQLITE_MEMDEBUG)
364 {
drh49e4fd72008-02-19 15:15:15 +0000365 extern int sqlite3MemdebugMallocCount();
366 nMalloc = sqlite3MemdebugMallocCount();
danielk1977a7a8e142008-02-13 18:25:27 +0000367 }
368#endif
369 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
370 return TCL_OK;
371}
372
drh2f999a62007-08-15 19:16:43 +0000373
374/*
danielk1977a1644fd2007-08-29 12:31:25 +0000375** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
376**
377** where options are:
378**
drh643167f2008-01-22 21:30:53 +0000379** -repeat <count>
danielk1977a1644fd2007-08-29 12:31:25 +0000380** -benigncnt <varname>
drh0e6f1542007-08-15 20:41:28 +0000381**
382** Arrange for a simulated malloc() failure after COUNTER successes.
drh643167f2008-01-22 21:30:53 +0000383** If a repeat count is specified, the fault is repeated that many
384** times.
drh0e6f1542007-08-15 20:41:28 +0000385**
386** Each call to this routine overrides the prior counter value.
387** This routine returns the number of simulated failures that have
388** happened since the previous call to this routine.
389**
390** To disable simulated failures, use a COUNTER of -1.
391*/
392static int test_memdebug_fail(
393 void * clientData,
394 Tcl_Interp *interp,
395 int objc,
396 Tcl_Obj *CONST objv[]
397){
danielk1977a1644fd2007-08-29 12:31:25 +0000398 int ii;
drh0e6f1542007-08-15 20:41:28 +0000399 int iFail;
drh643167f2008-01-22 21:30:53 +0000400 int nRepeat = 1;
danielk1977a1644fd2007-08-29 12:31:25 +0000401 Tcl_Obj *pBenignCnt = 0;
drh643167f2008-01-22 21:30:53 +0000402 int nBenign;
drh0e6f1542007-08-15 20:41:28 +0000403 int nFail = 0;
danielk1977a1644fd2007-08-29 12:31:25 +0000404
405 if( objc<2 ){
406 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
drh0e6f1542007-08-15 20:41:28 +0000407 return TCL_ERROR;
408 }
409 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +0000410
411 for(ii=2; ii<objc; ii+=2){
412 int nOption;
413 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
414 char *zErr = 0;
415
416 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
417 if( ii==(objc-1) ){
418 zErr = "option requires an argument: ";
419 }else{
drh643167f2008-01-22 21:30:53 +0000420 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
danielk1977a1644fd2007-08-29 12:31:25 +0000421 return TCL_ERROR;
422 }
423 }
424 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
425 if( ii==(objc-1) ){
426 zErr = "option requires an argument: ";
427 }else{
428 pBenignCnt = objv[ii+1];
429 }
430 }else{
431 zErr = "unknown option: ";
432 }
433
434 if( zErr ){
435 Tcl_AppendResult(interp, zErr, zOption, 0);
436 return TCL_ERROR;
437 }
drhed138fb2007-08-22 22:04:37 +0000438 }
danielk1977a1644fd2007-08-29 12:31:25 +0000439
drh77db4c02008-03-18 13:01:38 +0000440 sqlite3_test_control(-12345); /* Just to stress the test_control interface */
drhed13d982008-01-31 14:43:24 +0000441 nBenign = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES,
442 SQLITE_FAULTINJECTOR_MALLOC);
443 nFail = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_FAILURES,
444 SQLITE_FAULTINJECTOR_MALLOC);
445 sqlite3_test_control(SQLITE_TESTCTRL_FAULT_CONFIG,
446 SQLITE_FAULTINJECTOR_MALLOC, iFail, nRepeat);
drh643167f2008-01-22 21:30:53 +0000447 if( pBenignCnt ){
448 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
drh0e6f1542007-08-15 20:41:28 +0000449 }
drh0e6f1542007-08-15 20:41:28 +0000450 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
451 return TCL_OK;
452}
453
danielk1977cd037242007-08-30 15:46:06 +0000454/*
455** Usage: sqlite3_memdebug_pending
456**
457** Return the number of malloc() calls that will succeed before a
458** simulated failure occurs. A negative return value indicates that
459** no malloc() failure is scheduled.
460*/
461static int test_memdebug_pending(
462 void * clientData,
463 Tcl_Interp *interp,
464 int objc,
465 Tcl_Obj *CONST objv[]
466){
drh5efaf072008-03-18 00:07:10 +0000467 int nPending;
danielk1977cd037242007-08-30 15:46:06 +0000468 if( objc!=1 ){
469 Tcl_WrongNumArgs(interp, 1, objv, "");
470 return TCL_ERROR;
471 }
drh5efaf072008-03-18 00:07:10 +0000472 nPending = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_PENDING,
473 SQLITE_FAULTINJECTOR_MALLOC);
474 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
danielk1977cd037242007-08-30 15:46:06 +0000475 return TCL_OK;
476}
477
drh0e6f1542007-08-15 20:41:28 +0000478
479/*
drh4a50aac2007-08-23 02:47:53 +0000480** Usage: sqlite3_memdebug_settitle TITLE
481**
482** Set a title string stored with each allocation. The TITLE is
483** typically the name of the test that was running when the
484** allocation occurred. The TITLE is stored with the allocation
485** and can be used to figure out which tests are leaking memory.
486**
487** Each title overwrite the previous.
488*/
489static int test_memdebug_settitle(
490 void * clientData,
491 Tcl_Interp *interp,
492 int objc,
493 Tcl_Obj *CONST objv[]
494){
495 const char *zTitle;
496 if( objc!=2 ){
497 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
498 return TCL_ERROR;
499 }
500 zTitle = Tcl_GetString(objv[1]);
501#ifdef SQLITE_MEMDEBUG
502 {
drh49e4fd72008-02-19 15:15:15 +0000503 extern int sqlite3MemdebugSettitle(const char*);
504 sqlite3MemdebugSettitle(zTitle);
drh4a50aac2007-08-23 02:47:53 +0000505 }
506#endif
507 return TCL_OK;
508}
509
danielk1977cd3e8f72008-03-25 09:47:35 +0000510#define MALLOC_LOG_FRAMES 10
danielk19776f332c12008-03-21 14:22:44 +0000511static Tcl_HashTable aMallocLog;
512static int mallocLogEnabled = 0;
513
514typedef struct MallocLog MallocLog;
515struct MallocLog {
516 int nCall;
517 int nByte;
518};
519
520static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
521 if( mallocLogEnabled ){
522 MallocLog *pLog;
523 Tcl_HashEntry *pEntry;
524 int isNew;
525
526 int aKey[MALLOC_LOG_FRAMES];
527 int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
528
529 memset(aKey, 0, nKey);
530 if( (sizeof(void*)*nFrame)<nKey ){
531 nKey = nFrame*sizeof(void*);
532 }
533 memcpy(aKey, aFrame, nKey);
534
535 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
536 if( isNew ){
537 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
538 memset(pLog, 0, sizeof(MallocLog));
539 Tcl_SetHashValue(pEntry, (ClientData)pLog);
540 }else{
541 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
542 }
543
544 pLog->nCall++;
545 pLog->nByte += nByte;
546 }
547}
548
549static int test_memdebug_log(
550 void * clientData,
551 Tcl_Interp *interp,
552 int objc,
553 Tcl_Obj *CONST objv[]
554){
555 static int isInit = 0;
556 int iSub;
557
558 enum MB_enum { MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR };
559 static const char *MB_strs[] = { "start", "stop", "dump", "clear" };
560
561 if( !isInit ){
562#ifdef SQLITE_MEMDEBUG
563 extern void sqlite3MemdebugBacktraceCallback(
564 void (*xBacktrace)(int, int, void **));
565 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
566#endif
567 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
568 isInit = 1;
569 }
570
571 if( objc<2 ){
572 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
573 }
574 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
575 return TCL_ERROR;
576 }
577
578 switch( (enum MB_enum)iSub ){
579 case MB_LOG_START:
580 mallocLogEnabled = 1;
581 break;
582 case MB_LOG_STOP:
583 mallocLogEnabled = 0;
584 break;
585 case MB_LOG_DUMP: {
586 Tcl_HashSearch search;
587 Tcl_HashEntry *pEntry;
588 Tcl_Obj *pRet = Tcl_NewObj();
589
590 assert(sizeof(int)==sizeof(void*));
591
592 for(
593 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
594 pEntry;
595 pEntry=Tcl_NextHashEntry(&search)
596 ){
597 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
598 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
599 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
600 int ii;
601
602 apElem[0] = Tcl_NewIntObj(pLog->nCall);
603 apElem[1] = Tcl_NewIntObj(pLog->nByte);
604 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
605 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
606 }
607
608 Tcl_ListObjAppendElement(interp, pRet,
609 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
610 );
611 }
612
613 Tcl_SetObjResult(interp, pRet);
614 break;
615 }
616 case MB_LOG_CLEAR: {
617 Tcl_HashSearch search;
618 Tcl_HashEntry *pEntry;
619 for(
620 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
621 pEntry;
622 pEntry=Tcl_NextHashEntry(&search)
623 ){
624 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
625 Tcl_Free((char *)pLog);
626 }
627 Tcl_DeleteHashTable(&aMallocLog);
628 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
629 }
630 }
631
632 return TCL_OK;
633}
drh4a50aac2007-08-23 02:47:53 +0000634
635/*
drh2f999a62007-08-15 19:16:43 +0000636** Register commands with the TCL interpreter.
637*/
638int Sqlitetest_malloc_Init(Tcl_Interp *interp){
639 static struct {
640 char *zName;
641 Tcl_ObjCmdProc *xProc;
642 } aObjCmd[] = {
643 { "sqlite3_malloc", test_malloc },
644 { "sqlite3_realloc", test_realloc },
645 { "sqlite3_free", test_free },
drh9c7a60d2007-10-19 17:47:24 +0000646 { "memset", test_memset },
647 { "memget", test_memget },
drh2f999a62007-08-15 19:16:43 +0000648 { "sqlite3_memory_used", test_memory_used },
649 { "sqlite3_memory_highwater", test_memory_highwater },
650 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace },
651 { "sqlite3_memdebug_dump", test_memdebug_dump },
drh0e6f1542007-08-15 20:41:28 +0000652 { "sqlite3_memdebug_fail", test_memdebug_fail },
danielk1977cd037242007-08-30 15:46:06 +0000653 { "sqlite3_memdebug_pending", test_memdebug_pending },
drh4a50aac2007-08-23 02:47:53 +0000654 { "sqlite3_memdebug_settitle", test_memdebug_settitle },
danielk1977a7a8e142008-02-13 18:25:27 +0000655 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
danielk19776f332c12008-03-21 14:22:44 +0000656 { "sqlite3_memdebug_log", test_memdebug_log },
drh2f999a62007-08-15 19:16:43 +0000657 };
658 int i;
659 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
660 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
661 }
662 return TCL_OK;
663}