blob: 59a2954f795e06cffe39fe37683f1ab1dc0915c4 [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**
danielk1977d09414c2008-06-19 18:17:49 +000016** $Id: test_malloc.c,v 1.26 2008/06/19 18:17:50 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
danielk1977d09414c2008-06-19 18:17:49 +000024const char *sqlite3TestErrorName(int);
25
drh2f999a62007-08-15 19:16:43 +000026/*
27** Transform pointers to text and back again
28*/
29static void pointerToText(void *p, char *z){
30 static const char zHex[] = "0123456789abcdef";
31 int i, k;
drh4a50aac2007-08-23 02:47:53 +000032 unsigned int u;
33 sqlite3_uint64 n;
34 if( sizeof(n)==sizeof(p) ){
35 memcpy(&n, &p, sizeof(p));
36 }else if( sizeof(u)==sizeof(p) ){
37 memcpy(&u, &p, sizeof(u));
38 n = u;
39 }else{
40 assert( 0 );
41 }
drh2f999a62007-08-15 19:16:43 +000042 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
43 z[k] = zHex[n&0xf];
44 n >>= 4;
45 }
46 z[sizeof(p)*2] = 0;
47}
48static int hexToInt(int h){
49 if( h>='0' && h<='9' ){
50 return h - '0';
51 }else if( h>='a' && h<='f' ){
52 return h - 'a' + 10;
53 }else{
54 return -1;
55 }
56}
57static int textToPointer(const char *z, void **pp){
58 sqlite3_uint64 n = 0;
59 int i;
drh4a50aac2007-08-23 02:47:53 +000060 unsigned int u;
drh2f999a62007-08-15 19:16:43 +000061 for(i=0; i<sizeof(void*)*2 && z[0]; i++){
62 int v;
63 v = hexToInt(*z++);
64 if( v<0 ) return TCL_ERROR;
65 n = n*16 + v;
66 }
67 if( *z!=0 ) return TCL_ERROR;
drh4a50aac2007-08-23 02:47:53 +000068 if( sizeof(n)==sizeof(*pp) ){
69 memcpy(pp, &n, sizeof(n));
70 }else if( sizeof(u)==sizeof(*pp) ){
71 u = (unsigned int)n;
72 memcpy(pp, &u, sizeof(u));
73 }else{
74 assert( 0 );
75 }
drh2f999a62007-08-15 19:16:43 +000076 return TCL_OK;
77}
78
79/*
80** Usage: sqlite3_malloc NBYTES
81**
82** Raw test interface for sqlite3_malloc().
83*/
84static int test_malloc(
85 void * clientData,
86 Tcl_Interp *interp,
87 int objc,
88 Tcl_Obj *CONST objv[]
89){
90 int nByte;
91 void *p;
92 char zOut[100];
93 if( objc!=2 ){
94 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
95 return TCL_ERROR;
96 }
97 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
98 p = sqlite3_malloc((unsigned)nByte);
99 pointerToText(p, zOut);
100 Tcl_AppendResult(interp, zOut, NULL);
101 return TCL_OK;
102}
103
104/*
105** Usage: sqlite3_realloc PRIOR NBYTES
106**
107** Raw test interface for sqlite3_realloc().
108*/
109static int test_realloc(
110 void * clientData,
111 Tcl_Interp *interp,
112 int objc,
113 Tcl_Obj *CONST objv[]
114){
115 int nByte;
116 void *pPrior, *p;
117 char zOut[100];
118 if( objc!=3 ){
119 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
120 return TCL_ERROR;
121 }
122 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
123 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
124 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
125 return TCL_ERROR;
126 }
127 p = sqlite3_realloc(pPrior, (unsigned)nByte);
128 pointerToText(p, zOut);
129 Tcl_AppendResult(interp, zOut, NULL);
130 return TCL_OK;
131}
132
133
134/*
135** Usage: sqlite3_free PRIOR
136**
137** Raw test interface for sqlite3_free().
138*/
139static int test_free(
140 void * clientData,
141 Tcl_Interp *interp,
142 int objc,
143 Tcl_Obj *CONST objv[]
144){
145 void *pPrior;
146 if( objc!=2 ){
147 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
148 return TCL_ERROR;
149 }
150 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
151 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
152 return TCL_ERROR;
153 }
154 sqlite3_free(pPrior);
155 return TCL_OK;
156}
157
158/*
drh9c7a60d2007-10-19 17:47:24 +0000159** These routines are in test_hexio.c
160*/
161int sqlite3TestHexToBin(const char *, int, char *);
162int sqlite3TestBinToHex(char*,int);
163
164/*
165** Usage: memset ADDRESS SIZE HEX
166**
167** Set a chunk of memory (obtained from malloc, probably) to a
168** specified hex pattern.
169*/
170static int test_memset(
171 void * clientData,
172 Tcl_Interp *interp,
173 int objc,
174 Tcl_Obj *CONST objv[]
175){
176 void *p;
177 int size, n, i;
178 char *zHex;
179 char *zOut;
180 char zBin[100];
181
182 if( objc!=4 ){
183 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
184 return TCL_ERROR;
185 }
186 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
187 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
188 return TCL_ERROR;
189 }
190 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
191 return TCL_ERROR;
192 }
193 if( size<=0 ){
194 Tcl_AppendResult(interp, "size must be positive", (char*)0);
195 return TCL_ERROR;
196 }
197 zHex = Tcl_GetStringFromObj(objv[3], &n);
198 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
199 n = sqlite3TestHexToBin(zHex, n, zBin);
200 if( n==0 ){
201 Tcl_AppendResult(interp, "no data", (char*)0);
202 return TCL_ERROR;
203 }
204 zOut = p;
205 for(i=0; i<size; i++){
206 zOut[i] = zBin[i%n];
207 }
208 return TCL_OK;
209}
210
211/*
212** Usage: memget ADDRESS SIZE
213**
214** Return memory as hexadecimal text.
215*/
216static int test_memget(
217 void * clientData,
218 Tcl_Interp *interp,
219 int objc,
220 Tcl_Obj *CONST objv[]
221){
222 void *p;
223 int size, n;
224 char *zBin;
225 char zHex[100];
226
227 if( objc!=3 ){
228 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
229 return TCL_ERROR;
230 }
231 if( textToPointer(Tcl_GetString(objv[1]), &p) ){
232 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
233 return TCL_ERROR;
234 }
235 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
236 return TCL_ERROR;
237 }
238 if( size<=0 ){
239 Tcl_AppendResult(interp, "size must be positive", (char*)0);
240 return TCL_ERROR;
241 }
242 zBin = p;
243 while( size>0 ){
244 if( size>(sizeof(zHex)-1)/2 ){
245 n = (sizeof(zHex)-1)/2;
246 }else{
247 n = size;
248 }
249 memcpy(zHex, zBin, n);
250 zBin += n;
251 size -= n;
252 sqlite3TestBinToHex(zHex, n);
253 Tcl_AppendResult(interp, zHex, (char*)0);
254 }
255 return TCL_OK;
256}
257
258/*
drh2f999a62007-08-15 19:16:43 +0000259** Usage: sqlite3_memory_used
260**
261** Raw test interface for sqlite3_memory_used().
262*/
263static int test_memory_used(
264 void * clientData,
265 Tcl_Interp *interp,
266 int objc,
267 Tcl_Obj *CONST objv[]
268){
269 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
270 return TCL_OK;
271}
272
273/*
274** Usage: sqlite3_memory_highwater ?RESETFLAG?
275**
276** Raw test interface for sqlite3_memory_highwater().
277*/
278static int test_memory_highwater(
279 void * clientData,
280 Tcl_Interp *interp,
281 int objc,
282 Tcl_Obj *CONST objv[]
283){
284 int resetFlag = 0;
285 if( objc!=1 && objc!=2 ){
286 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
287 return TCL_ERROR;
288 }
289 if( objc==2 ){
290 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
291 }
292 Tcl_SetObjResult(interp,
293 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
294 return TCL_OK;
295}
296
297/*
298** Usage: sqlite3_memdebug_backtrace DEPTH
299**
300** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
301** then this routine is a no-op.
302*/
303static int test_memdebug_backtrace(
304 void * clientData,
305 Tcl_Interp *interp,
306 int objc,
307 Tcl_Obj *CONST objv[]
308){
309 int depth;
310 if( objc!=2 ){
311 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
312 return TCL_ERROR;
313 }
314 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
315#ifdef SQLITE_MEMDEBUG
316 {
drh49e4fd72008-02-19 15:15:15 +0000317 extern void sqlite3MemdebugBacktrace(int);
318 sqlite3MemdebugBacktrace(depth);
drh2f999a62007-08-15 19:16:43 +0000319 }
320#endif
321 return TCL_OK;
322}
323
324/*
325** Usage: sqlite3_memdebug_dump FILENAME
326**
327** Write a summary of unfreed memory to FILENAME.
328*/
329static int test_memdebug_dump(
330 void * clientData,
331 Tcl_Interp *interp,
332 int objc,
333 Tcl_Obj *CONST objv[]
334){
335 if( objc!=2 ){
336 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
337 return TCL_ERROR;
338 }
drh2d7636e2008-02-16 16:21:45 +0000339#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
340 || defined(SQLITE_POW2_MEMORY_SIZE)
drh2f999a62007-08-15 19:16:43 +0000341 {
drh49e4fd72008-02-19 15:15:15 +0000342 extern void sqlite3MemdebugDump(const char*);
343 sqlite3MemdebugDump(Tcl_GetString(objv[1]));
drh2f999a62007-08-15 19:16:43 +0000344 }
345#endif
346 return TCL_OK;
347}
348
danielk1977a7a8e142008-02-13 18:25:27 +0000349/*
350** Usage: sqlite3_memdebug_malloc_count
351**
352** Return the total number of times malloc() has been called.
353*/
354static int test_memdebug_malloc_count(
355 void * clientData,
356 Tcl_Interp *interp,
357 int objc,
358 Tcl_Obj *CONST objv[]
359){
360 int nMalloc = -1;
361 if( objc!=1 ){
362 Tcl_WrongNumArgs(interp, 1, objv, "");
363 return TCL_ERROR;
364 }
365#if defined(SQLITE_MEMDEBUG)
366 {
drh49e4fd72008-02-19 15:15:15 +0000367 extern int sqlite3MemdebugMallocCount();
368 nMalloc = sqlite3MemdebugMallocCount();
danielk1977a7a8e142008-02-13 18:25:27 +0000369 }
370#endif
371 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
372 return TCL_OK;
373}
374
drh2f999a62007-08-15 19:16:43 +0000375
376/*
danielk1977a1644fd2007-08-29 12:31:25 +0000377** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
378**
379** where options are:
380**
drh643167f2008-01-22 21:30:53 +0000381** -repeat <count>
danielk1977a1644fd2007-08-29 12:31:25 +0000382** -benigncnt <varname>
drh0e6f1542007-08-15 20:41:28 +0000383**
384** Arrange for a simulated malloc() failure after COUNTER successes.
drh643167f2008-01-22 21:30:53 +0000385** If a repeat count is specified, the fault is repeated that many
386** times.
drh0e6f1542007-08-15 20:41:28 +0000387**
388** Each call to this routine overrides the prior counter value.
389** This routine returns the number of simulated failures that have
390** happened since the previous call to this routine.
391**
392** To disable simulated failures, use a COUNTER of -1.
393*/
394static int test_memdebug_fail(
395 void * clientData,
396 Tcl_Interp *interp,
397 int objc,
398 Tcl_Obj *CONST objv[]
399){
danielk1977a1644fd2007-08-29 12:31:25 +0000400 int ii;
drh0e6f1542007-08-15 20:41:28 +0000401 int iFail;
drh643167f2008-01-22 21:30:53 +0000402 int nRepeat = 1;
danielk1977a1644fd2007-08-29 12:31:25 +0000403 Tcl_Obj *pBenignCnt = 0;
drh643167f2008-01-22 21:30:53 +0000404 int nBenign;
drh0e6f1542007-08-15 20:41:28 +0000405 int nFail = 0;
danielk1977a1644fd2007-08-29 12:31:25 +0000406
407 if( objc<2 ){
408 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
drh0e6f1542007-08-15 20:41:28 +0000409 return TCL_ERROR;
410 }
411 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +0000412
413 for(ii=2; ii<objc; ii+=2){
414 int nOption;
415 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
416 char *zErr = 0;
417
418 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
419 if( ii==(objc-1) ){
420 zErr = "option requires an argument: ";
421 }else{
drh643167f2008-01-22 21:30:53 +0000422 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
danielk1977a1644fd2007-08-29 12:31:25 +0000423 return TCL_ERROR;
424 }
425 }
426 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
427 if( ii==(objc-1) ){
428 zErr = "option requires an argument: ";
429 }else{
430 pBenignCnt = objv[ii+1];
431 }
432 }else{
433 zErr = "unknown option: ";
434 }
435
436 if( zErr ){
437 Tcl_AppendResult(interp, zErr, zOption, 0);
438 return TCL_ERROR;
439 }
drhed138fb2007-08-22 22:04:37 +0000440 }
danielk1977a1644fd2007-08-29 12:31:25 +0000441
drh77db4c02008-03-18 13:01:38 +0000442 sqlite3_test_control(-12345); /* Just to stress the test_control interface */
drhed13d982008-01-31 14:43:24 +0000443 nBenign = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES,
444 SQLITE_FAULTINJECTOR_MALLOC);
445 nFail = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_FAILURES,
446 SQLITE_FAULTINJECTOR_MALLOC);
447 sqlite3_test_control(SQLITE_TESTCTRL_FAULT_CONFIG,
448 SQLITE_FAULTINJECTOR_MALLOC, iFail, nRepeat);
drh643167f2008-01-22 21:30:53 +0000449 if( pBenignCnt ){
450 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
drh0e6f1542007-08-15 20:41:28 +0000451 }
drh0e6f1542007-08-15 20:41:28 +0000452 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
453 return TCL_OK;
454}
455
danielk1977cd037242007-08-30 15:46:06 +0000456/*
457** Usage: sqlite3_memdebug_pending
458**
459** Return the number of malloc() calls that will succeed before a
460** simulated failure occurs. A negative return value indicates that
461** no malloc() failure is scheduled.
462*/
463static int test_memdebug_pending(
464 void * clientData,
465 Tcl_Interp *interp,
466 int objc,
467 Tcl_Obj *CONST objv[]
468){
drh5efaf072008-03-18 00:07:10 +0000469 int nPending;
danielk1977cd037242007-08-30 15:46:06 +0000470 if( objc!=1 ){
471 Tcl_WrongNumArgs(interp, 1, objv, "");
472 return TCL_ERROR;
473 }
drh5efaf072008-03-18 00:07:10 +0000474 nPending = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_PENDING,
475 SQLITE_FAULTINJECTOR_MALLOC);
476 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
danielk1977cd037242007-08-30 15:46:06 +0000477 return TCL_OK;
478}
479
drh0e6f1542007-08-15 20:41:28 +0000480
481/*
drh4a50aac2007-08-23 02:47:53 +0000482** Usage: sqlite3_memdebug_settitle TITLE
483**
484** Set a title string stored with each allocation. The TITLE is
485** typically the name of the test that was running when the
486** allocation occurred. The TITLE is stored with the allocation
487** and can be used to figure out which tests are leaking memory.
488**
489** Each title overwrite the previous.
490*/
491static int test_memdebug_settitle(
492 void * clientData,
493 Tcl_Interp *interp,
494 int objc,
495 Tcl_Obj *CONST objv[]
496){
497 const char *zTitle;
498 if( objc!=2 ){
499 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
500 return TCL_ERROR;
501 }
502 zTitle = Tcl_GetString(objv[1]);
503#ifdef SQLITE_MEMDEBUG
504 {
drh49e4fd72008-02-19 15:15:15 +0000505 extern int sqlite3MemdebugSettitle(const char*);
506 sqlite3MemdebugSettitle(zTitle);
drh4a50aac2007-08-23 02:47:53 +0000507 }
508#endif
509 return TCL_OK;
510}
511
danielk1977cd3e8f72008-03-25 09:47:35 +0000512#define MALLOC_LOG_FRAMES 10
danielk19776f332c12008-03-21 14:22:44 +0000513static Tcl_HashTable aMallocLog;
514static int mallocLogEnabled = 0;
515
516typedef struct MallocLog MallocLog;
517struct MallocLog {
518 int nCall;
519 int nByte;
520};
521
shaneafdd23a2008-05-29 02:57:47 +0000522#ifdef SQLITE_MEMDEBUG
danielk19776f332c12008-03-21 14:22:44 +0000523static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
524 if( mallocLogEnabled ){
525 MallocLog *pLog;
526 Tcl_HashEntry *pEntry;
527 int isNew;
528
529 int aKey[MALLOC_LOG_FRAMES];
530 int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
531
532 memset(aKey, 0, nKey);
533 if( (sizeof(void*)*nFrame)<nKey ){
534 nKey = nFrame*sizeof(void*);
535 }
536 memcpy(aKey, aFrame, nKey);
537
538 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
539 if( isNew ){
540 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
541 memset(pLog, 0, sizeof(MallocLog));
542 Tcl_SetHashValue(pEntry, (ClientData)pLog);
543 }else{
544 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
545 }
546
547 pLog->nCall++;
548 pLog->nByte += nByte;
549 }
550}
shaneafdd23a2008-05-29 02:57:47 +0000551#endif /* SQLITE_MEMDEBUG */
danielk19776f332c12008-03-21 14:22:44 +0000552
danielk19775f096132008-03-28 15:44:09 +0000553static void test_memdebug_log_clear(){
danielk1977dbdc4d42008-03-28 07:42:53 +0000554 Tcl_HashSearch search;
555 Tcl_HashEntry *pEntry;
556 for(
557 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
558 pEntry;
559 pEntry=Tcl_NextHashEntry(&search)
560 ){
561 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
562 Tcl_Free((char *)pLog);
563 }
564 Tcl_DeleteHashTable(&aMallocLog);
565 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
566}
567
danielk19776f332c12008-03-21 14:22:44 +0000568static int test_memdebug_log(
569 void * clientData,
570 Tcl_Interp *interp,
571 int objc,
572 Tcl_Obj *CONST objv[]
573){
574 static int isInit = 0;
575 int iSub;
576
danielk1977dbdc4d42008-03-28 07:42:53 +0000577 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
578 enum MB_enum {
579 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
580 };
danielk19776f332c12008-03-21 14:22:44 +0000581
582 if( !isInit ){
583#ifdef SQLITE_MEMDEBUG
584 extern void sqlite3MemdebugBacktraceCallback(
585 void (*xBacktrace)(int, int, void **));
586 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
587#endif
588 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
589 isInit = 1;
590 }
591
592 if( objc<2 ){
593 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
594 }
595 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
596 return TCL_ERROR;
597 }
598
599 switch( (enum MB_enum)iSub ){
600 case MB_LOG_START:
601 mallocLogEnabled = 1;
602 break;
603 case MB_LOG_STOP:
604 mallocLogEnabled = 0;
605 break;
606 case MB_LOG_DUMP: {
607 Tcl_HashSearch search;
608 Tcl_HashEntry *pEntry;
609 Tcl_Obj *pRet = Tcl_NewObj();
610
611 assert(sizeof(int)==sizeof(void*));
612
613 for(
614 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
615 pEntry;
616 pEntry=Tcl_NextHashEntry(&search)
617 ){
618 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
619 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
620 int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
621 int ii;
622
623 apElem[0] = Tcl_NewIntObj(pLog->nCall);
624 apElem[1] = Tcl_NewIntObj(pLog->nByte);
625 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
626 apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
627 }
628
629 Tcl_ListObjAppendElement(interp, pRet,
630 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
631 );
632 }
633
634 Tcl_SetObjResult(interp, pRet);
635 break;
636 }
637 case MB_LOG_CLEAR: {
danielk1977dbdc4d42008-03-28 07:42:53 +0000638 test_memdebug_log_clear();
639 break;
640 }
641
642 case MB_LOG_SYNC: {
drhb9404922008-03-28 12:53:38 +0000643#ifdef SQLITE_MEMDEBUG
danielk1977dbdc4d42008-03-28 07:42:53 +0000644 extern void sqlite3MemdebugSync();
645 test_memdebug_log_clear();
646 mallocLogEnabled = 1;
647 sqlite3MemdebugSync();
drhb9404922008-03-28 12:53:38 +0000648#endif
danielk1977dbdc4d42008-03-28 07:42:53 +0000649 break;
danielk19776f332c12008-03-21 14:22:44 +0000650 }
651 }
652
653 return TCL_OK;
654}
drh4a50aac2007-08-23 02:47:53 +0000655
656/*
drh9ac3fe92008-06-18 18:12:04 +0000657** Usage: sqlite3_config_scratch SIZE N
658**
659** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
660** The buffer is static and is of limited size. N might be
661** adjusted downward as needed to accomodate the requested size.
662** The revised value of N is returned.
663**
664** A negative SIZE causes the buffer pointer to be NULL.
665*/
666static int test_config_scratch(
667 void * clientData,
668 Tcl_Interp *interp,
669 int objc,
670 Tcl_Obj *CONST objv[]
671){
672 int sz, N, rc;
673 Tcl_Obj *pResult;
drhf7141992008-06-19 00:16:08 +0000674 static char buf[30000];
drh9ac3fe92008-06-18 18:12:04 +0000675 if( objc!=3 ){
676 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
677 return TCL_ERROR;
678 }
drhf7141992008-06-19 00:16:08 +0000679 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
680 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh9ac3fe92008-06-18 18:12:04 +0000681 if( sz<0 ){
682 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
drhf7141992008-06-19 00:16:08 +0000683 }else{
drh9ac3fe92008-06-18 18:12:04 +0000684 int mx = sizeof(buf)/(sz+4);
685 if( N>mx ) N = mx;
686 rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
687 }
688 pResult = Tcl_NewObj();
689 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
690 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
691 Tcl_SetObjResult(interp, pResult);
692 return TCL_OK;
693}
694
695/*
696** Usage: sqlite3_config_pagecache SIZE N
697**
698** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
699** The buffer is static and is of limited size. N might be
700** adjusted downward as needed to accomodate the requested size.
701** The revised value of N is returned.
702**
703** A negative SIZE causes the buffer pointer to be NULL.
704*/
705static int test_config_pagecache(
706 void * clientData,
707 Tcl_Interp *interp,
708 int objc,
709 Tcl_Obj *CONST objv[]
710){
711 int sz, N, rc;
712 Tcl_Obj *pResult;
713 static char buf[100000];
714 if( objc!=3 ){
715 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
716 return TCL_ERROR;
717 }
drhf7141992008-06-19 00:16:08 +0000718 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
719 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
drh9ac3fe92008-06-18 18:12:04 +0000720 if( sz<0 ){
drhf7141992008-06-19 00:16:08 +0000721 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
722 }else{
drh9ac3fe92008-06-18 18:12:04 +0000723 int mx = sizeof(buf)/(sz+4);
724 if( N>mx ) N = mx;
725 rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
726 }
727 pResult = Tcl_NewObj();
728 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
729 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
730 Tcl_SetObjResult(interp, pResult);
731 return TCL_OK;
732}
733
drhf7141992008-06-19 00:16:08 +0000734/*
735** Usage: sqlite3_status OPCODE RESETFLAG
736**
737** Return a list of three elements which are the sqlite3_status() return
738** code, the current value, and the high-water mark value.
739*/
740static int test_status(
741 void * clientData,
742 Tcl_Interp *interp,
743 int objc,
744 Tcl_Obj *CONST objv[]
745){
746 int rc, iValue, mxValue;
747 int i, op, resetFlag;
748 const char *zOpName;
749 static const struct {
750 const char *zName;
751 int op;
752 } aOp[] = {
753 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
754 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
755 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
756 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
757 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
758 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
759 };
760 Tcl_Obj *pResult;
761 if( objc!=3 ){
762 Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
763 return TCL_ERROR;
764 }
765 zOpName = Tcl_GetString(objv[1]);
766 for(i=0; i<ArraySize(aOp); i++){
767 if( strcmp(aOp[i].zName, zOpName)==0 ){
768 op = aOp[i].op;
769 break;
770 }
771 }
772 if( i>=ArraySize(aOp) ){
773 if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
774 }
775 if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
776 rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
777 pResult = Tcl_NewObj();
778 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
779 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
780 Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
781 Tcl_SetObjResult(interp, pResult);
782 return TCL_OK;
783}
drh9ac3fe92008-06-18 18:12:04 +0000784
785/*
danielk1977d09414c2008-06-19 18:17:49 +0000786** install_malloc_faultsim BOOLEAN
787*/
788static int test_install_malloc_faultsim(
789 void * clientData,
790 Tcl_Interp *interp,
791 int objc,
792 Tcl_Obj *CONST objv[]
793){
794 int rc;
795 int isInstall;
796
797 if( objc!=2 ){
798 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
799 return TCL_ERROR;
800 }
801 if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
802 return TCL_ERROR;
803 }
804 rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, isInstall);
805 Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
806 return TCL_OK;
807}
808
809/*
drh2f999a62007-08-15 19:16:43 +0000810** Register commands with the TCL interpreter.
811*/
812int Sqlitetest_malloc_Init(Tcl_Interp *interp){
813 static struct {
814 char *zName;
815 Tcl_ObjCmdProc *xProc;
816 } aObjCmd[] = {
817 { "sqlite3_malloc", test_malloc },
818 { "sqlite3_realloc", test_realloc },
819 { "sqlite3_free", test_free },
drh9c7a60d2007-10-19 17:47:24 +0000820 { "memset", test_memset },
821 { "memget", test_memget },
drh2f999a62007-08-15 19:16:43 +0000822 { "sqlite3_memory_used", test_memory_used },
823 { "sqlite3_memory_highwater", test_memory_highwater },
824 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace },
825 { "sqlite3_memdebug_dump", test_memdebug_dump },
drh0e6f1542007-08-15 20:41:28 +0000826 { "sqlite3_memdebug_fail", test_memdebug_fail },
danielk1977cd037242007-08-30 15:46:06 +0000827 { "sqlite3_memdebug_pending", test_memdebug_pending },
drh4a50aac2007-08-23 02:47:53 +0000828 { "sqlite3_memdebug_settitle", test_memdebug_settitle },
danielk1977a7a8e142008-02-13 18:25:27 +0000829 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
drh9ac3fe92008-06-18 18:12:04 +0000830 { "sqlite3_memdebug_log", test_memdebug_log },
831 { "sqlite3_config_scratch", test_config_scratch },
832 { "sqlite3_config_pagecache", test_config_pagecache },
drhf7141992008-06-19 00:16:08 +0000833 { "sqlite3_status", test_status },
danielk1977d09414c2008-06-19 18:17:49 +0000834
835 { "install_malloc_faultsim", test_install_malloc_faultsim },
drh2f999a62007-08-15 19:16:43 +0000836 };
837 int i;
838 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
839 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
840 }
841 return TCL_OK;
842}