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: #include "sqliteInt.h"
17: #include "tcl.h"
18: #include <stdlib.h>
19: #include <string.h>
20: #include <assert.h>
21:
22: /*
23: ** This structure is used to encapsulate the global state variables used
24: ** by malloc() fault simulation.
25: */
26: static struct MemFault {
27: int iCountdown; /* Number of pending successes before a failure */
28: int nRepeat; /* Number of times to repeat the failure */
29: int nBenign; /* Number of benign failures seen since last config */
30: int nFail; /* Number of failures seen since last config */
31: u8 enable; /* True if enabled */
32: int isInstalled; /* True if the fault simulation layer is installed */
33: int isBenignMode; /* True if malloc failures are considered benign */
34: sqlite3_mem_methods m; /* 'Real' malloc implementation */
35: } memfault;
36:
37: /*
38: ** This routine exists as a place to set a breakpoint that will
39: ** fire on any simulated malloc() failure.
40: */
41: static void sqlite3Fault(void){
42: static int cnt = 0;
43: cnt++;
44: }
45:
46: /*
47: ** Check to see if a fault should be simulated. Return true to simulate
48: ** the fault. Return false if the fault should not be simulated.
49: */
50: static int faultsimStep(void){
51: if( likely(!memfault.enable) ){
52: return 0;
53: }
54: if( memfault.iCountdown>0 ){
55: memfault.iCountdown--;
56: return 0;
57: }
58: sqlite3Fault();
59: memfault.nFail++;
60: if( memfault.isBenignMode>0 ){
61: memfault.nBenign++;
62: }
63: memfault.nRepeat--;
64: if( memfault.nRepeat<=0 ){
65: memfault.enable = 0;
66: }
67: return 1;
68: }
69:
70: /*
71: ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
72: ** logic.
73: */
74: static void *faultsimMalloc(int n){
75: void *p = 0;
76: if( !faultsimStep() ){
77: p = memfault.m.xMalloc(n);
78: }
79: return p;
80: }
81:
82:
83: /*
84: ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
85: ** logic.
86: */
87: static void *faultsimRealloc(void *pOld, int n){
88: void *p = 0;
89: if( !faultsimStep() ){
90: p = memfault.m.xRealloc(pOld, n);
91: }
92: return p;
93: }
94:
95: /*
96: ** The following method calls are passed directly through to the underlying
97: ** malloc system:
98: **
99: ** xFree
100: ** xSize
101: ** xRoundup
102: ** xInit
103: ** xShutdown
104: */
105: static void faultsimFree(void *p){
106: memfault.m.xFree(p);
107: }
108: static int faultsimSize(void *p){
109: return memfault.m.xSize(p);
110: }
111: static int faultsimRoundup(int n){
112: return memfault.m.xRoundup(n);
113: }
114: static int faultsimInit(void *p){
115: return memfault.m.xInit(memfault.m.pAppData);
116: }
117: static void faultsimShutdown(void *p){
118: memfault.m.xShutdown(memfault.m.pAppData);
119: }
120:
121: /*
122: ** This routine configures the malloc failure simulation. After
123: ** calling this routine, the next nDelay mallocs will succeed, followed
124: ** by a block of nRepeat failures, after which malloc() calls will begin
125: ** to succeed again.
126: */
127: static void faultsimConfig(int nDelay, int nRepeat){
128: memfault.iCountdown = nDelay;
129: memfault.nRepeat = nRepeat;
130: memfault.nBenign = 0;
131: memfault.nFail = 0;
132: memfault.enable = nDelay>=0;
133:
134: /* Sometimes, when running multi-threaded tests, the isBenignMode
135: ** variable is not properly incremented/decremented so that it is
136: ** 0 when not inside a benign malloc block. This doesn't affect
137: ** the multi-threaded tests, as they do not use this system. But
138: ** it does affect OOM tests run later in the same process. So
139: ** zero the variable here, just to be sure.
140: */
141: memfault.isBenignMode = 0;
142: }
143:
144: /*
145: ** Return the number of faults (both hard and benign faults) that have
146: ** occurred since the injector was last configured.
147: */
148: static int faultsimFailures(void){
149: return memfault.nFail;
150: }
151:
152: /*
153: ** Return the number of benign faults that have occurred since the
154: ** injector was last configured.
155: */
156: static int faultsimBenignFailures(void){
157: return memfault.nBenign;
158: }
159:
160: /*
161: ** Return the number of successes that will occur before the next failure.
162: ** If no failures are scheduled, return -1.
163: */
164: static int faultsimPending(void){
165: if( memfault.enable ){
166: return memfault.iCountdown;
167: }else{
168: return -1;
169: }
170: }
171:
172:
173: static void faultsimBeginBenign(void){
174: memfault.isBenignMode++;
175: }
176: static void faultsimEndBenign(void){
177: memfault.isBenignMode--;
178: }
179:
180: /*
181: ** Add or remove the fault-simulation layer using sqlite3_config(). If
182: ** the argument is non-zero, the
183: */
184: static int faultsimInstall(int install){
185: static struct sqlite3_mem_methods m = {
186: faultsimMalloc, /* xMalloc */
187: faultsimFree, /* xFree */
188: faultsimRealloc, /* xRealloc */
189: faultsimSize, /* xSize */
190: faultsimRoundup, /* xRoundup */
191: faultsimInit, /* xInit */
192: faultsimShutdown, /* xShutdown */
193: 0 /* pAppData */
194: };
195: int rc;
196:
197: install = (install ? 1 : 0);
198: assert(memfault.isInstalled==1 || memfault.isInstalled==0);
199:
200: if( install==memfault.isInstalled ){
201: return SQLITE_ERROR;
202: }
203:
204: if( install ){
205: rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
206: assert(memfault.m.xMalloc);
207: if( rc==SQLITE_OK ){
208: rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
209: }
210: sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
211: faultsimBeginBenign, faultsimEndBenign
212: );
213: }else{
214: sqlite3_mem_methods m;
215: assert(memfault.m.xMalloc);
216:
217: /* One should be able to reset the default memory allocator by storing
218: ** a zeroed allocator then calling GETMALLOC. */
219: memset(&m, 0, sizeof(m));
220: sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
221: sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m);
222: assert( memcmp(&m, &memfault.m, sizeof(m))==0 );
223:
224: rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);
225: sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0);
226: }
227:
228: if( rc==SQLITE_OK ){
229: memfault.isInstalled = 1;
230: }
231: return rc;
232: }
233:
234: #ifdef SQLITE_TEST
235:
236: /*
237: ** This function is implemented in test1.c. Returns a pointer to a static
238: ** buffer containing the symbolic SQLite error code that corresponds to
239: ** the least-significant 8-bits of the integer passed as an argument.
240: ** For example:
241: **
242: ** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
243: */
244: const char *sqlite3TestErrorName(int);
245:
246: /*
247: ** Transform pointers to text and back again
248: */
249: static void pointerToText(void *p, char *z){
250: static const char zHex[] = "0123456789abcdef";
251: int i, k;
252: unsigned int u;
253: sqlite3_uint64 n;
254: if( p==0 ){
255: strcpy(z, "0");
256: return;
257: }
258: if( sizeof(n)==sizeof(p) ){
259: memcpy(&n, &p, sizeof(p));
260: }else if( sizeof(u)==sizeof(p) ){
261: memcpy(&u, &p, sizeof(u));
262: n = u;
263: }else{
264: assert( 0 );
265: }
266: for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
267: z[k] = zHex[n&0xf];
268: n >>= 4;
269: }
270: z[sizeof(p)*2] = 0;
271: }
272: static int hexToInt(int h){
273: if( h>='0' && h<='9' ){
274: return h - '0';
275: }else if( h>='a' && h<='f' ){
276: return h - 'a' + 10;
277: }else{
278: return -1;
279: }
280: }
281: static int textToPointer(const char *z, void **pp){
282: sqlite3_uint64 n = 0;
283: int i;
284: unsigned int u;
285: for(i=0; i<sizeof(void*)*2 && z[0]; i++){
286: int v;
287: v = hexToInt(*z++);
288: if( v<0 ) return TCL_ERROR;
289: n = n*16 + v;
290: }
291: if( *z!=0 ) return TCL_ERROR;
292: if( sizeof(n)==sizeof(*pp) ){
293: memcpy(pp, &n, sizeof(n));
294: }else if( sizeof(u)==sizeof(*pp) ){
295: u = (unsigned int)n;
296: memcpy(pp, &u, sizeof(u));
297: }else{
298: assert( 0 );
299: }
300: return TCL_OK;
301: }
302:
303: /*
304: ** Usage: sqlite3_malloc NBYTES
305: **
306: ** Raw test interface for sqlite3_malloc().
307: */
308: static int test_malloc(
309: void * clientData,
310: Tcl_Interp *interp,
311: int objc,
312: Tcl_Obj *CONST objv[]
313: ){
314: int nByte;
315: void *p;
316: char zOut[100];
317: if( objc!=2 ){
318: Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
319: return TCL_ERROR;
320: }
321: if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;
322: p = sqlite3_malloc((unsigned)nByte);
323: pointerToText(p, zOut);
324: Tcl_AppendResult(interp, zOut, NULL);
325: return TCL_OK;
326: }
327:
328: /*
329: ** Usage: sqlite3_realloc PRIOR NBYTES
330: **
331: ** Raw test interface for sqlite3_realloc().
332: */
333: static int test_realloc(
334: void * clientData,
335: Tcl_Interp *interp,
336: int objc,
337: Tcl_Obj *CONST objv[]
338: ){
339: int nByte;
340: void *pPrior, *p;
341: char zOut[100];
342: if( objc!=3 ){
343: Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
344: return TCL_ERROR;
345: }
346: if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;
347: if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
348: Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
349: return TCL_ERROR;
350: }
351: p = sqlite3_realloc(pPrior, (unsigned)nByte);
352: pointerToText(p, zOut);
353: Tcl_AppendResult(interp, zOut, NULL);
354: return TCL_OK;
355: }
356:
357: /*
358: ** Usage: sqlite3_free PRIOR
359: **
360: ** Raw test interface for sqlite3_free().
361: */
362: static int test_free(
363: void * clientData,
364: Tcl_Interp *interp,
365: int objc,
366: Tcl_Obj *CONST objv[]
367: ){
368: void *pPrior;
369: if( objc!=2 ){
370: Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
371: return TCL_ERROR;
372: }
373: if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){
374: Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
375: return TCL_ERROR;
376: }
377: sqlite3_free(pPrior);
378: return TCL_OK;
379: }
380:
381: /*
382: ** These routines are in test_hexio.c
383: */
384: int sqlite3TestHexToBin(const char *, int, char *);
385: int sqlite3TestBinToHex(char*,int);
386:
387: /*
388: ** Usage: memset ADDRESS SIZE HEX
389: **
390: ** Set a chunk of memory (obtained from malloc, probably) to a
391: ** specified hex pattern.
392: */
393: static int test_memset(
394: void * clientData,
395: Tcl_Interp *interp,
396: int objc,
397: Tcl_Obj *CONST objv[]
398: ){
399: void *p;
400: int size, n, i;
401: char *zHex;
402: char *zOut;
403: char zBin[100];
404:
405: if( objc!=4 ){
406: Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
407: return TCL_ERROR;
408: }
409: if( textToPointer(Tcl_GetString(objv[1]), &p) ){
410: Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
411: return TCL_ERROR;
412: }
413: if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
414: return TCL_ERROR;
415: }
416: if( size<=0 ){
417: Tcl_AppendResult(interp, "size must be positive", (char*)0);
418: return TCL_ERROR;
419: }
420: zHex = Tcl_GetStringFromObj(objv[3], &n);
421: if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
422: n = sqlite3TestHexToBin(zHex, n, zBin);
423: if( n==0 ){
424: Tcl_AppendResult(interp, "no data", (char*)0);
425: return TCL_ERROR;
426: }
427: zOut = p;
428: for(i=0; i<size; i++){
429: zOut[i] = zBin[i%n];
430: }
431: return TCL_OK;
432: }
433:
434: /*
435: ** Usage: memget ADDRESS SIZE
436: **
437: ** Return memory as hexadecimal text.
438: */
439: static int test_memget(
440: void * clientData,
441: Tcl_Interp *interp,
442: int objc,
443: Tcl_Obj *CONST objv[]
444: ){
445: void *p;
446: int size, n;
447: char *zBin;
448: char zHex[100];
449:
450: if( objc!=3 ){
451: Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
452: return TCL_ERROR;
453: }
454: if( textToPointer(Tcl_GetString(objv[1]), &p) ){
455: Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);
456: return TCL_ERROR;
457: }
458: if( Tcl_GetIntFromObj(interp, objv[2], &size) ){
459: return TCL_ERROR;
460: }
461: if( size<=0 ){
462: Tcl_AppendResult(interp, "size must be positive", (char*)0);
463: return TCL_ERROR;
464: }
465: zBin = p;
466: while( size>0 ){
467: if( size>(sizeof(zHex)-1)/2 ){
468: n = (sizeof(zHex)-1)/2;
469: }else{
470: n = size;
471: }
472: memcpy(zHex, zBin, n);
473: zBin += n;
474: size -= n;
475: sqlite3TestBinToHex(zHex, n);
476: Tcl_AppendResult(interp, zHex, (char*)0);
477: }
478: return TCL_OK;
479: }
480:
481: /*
482: ** Usage: sqlite3_memory_used
483: **
484: ** Raw test interface for sqlite3_memory_used().
485: */
486: static int test_memory_used(
487: void * clientData,
488: Tcl_Interp *interp,
489: int objc,
490: Tcl_Obj *CONST objv[]
491: ){
492: Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));
493: return TCL_OK;
494: }
495:
496: /*
497: ** Usage: sqlite3_memory_highwater ?RESETFLAG?
498: **
499: ** Raw test interface for sqlite3_memory_highwater().
500: */
501: static int test_memory_highwater(
502: void * clientData,
503: Tcl_Interp *interp,
504: int objc,
505: Tcl_Obj *CONST objv[]
506: ){
507: int resetFlag = 0;
508: if( objc!=1 && objc!=2 ){
509: Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");
510: return TCL_ERROR;
511: }
512: if( objc==2 ){
513: if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;
514: }
515: Tcl_SetObjResult(interp,
516: Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));
517: return TCL_OK;
518: }
519:
520: /*
521: ** Usage: sqlite3_memdebug_backtrace DEPTH
522: **
523: ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
524: ** then this routine is a no-op.
525: */
526: static int test_memdebug_backtrace(
527: void * clientData,
528: Tcl_Interp *interp,
529: int objc,
530: Tcl_Obj *CONST objv[]
531: ){
532: int depth;
533: if( objc!=2 ){
534: Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
535: return TCL_ERROR;
536: }
537: if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;
538: #ifdef SQLITE_MEMDEBUG
539: {
540: extern void sqlite3MemdebugBacktrace(int);
541: sqlite3MemdebugBacktrace(depth);
542: }
543: #endif
544: return TCL_OK;
545: }
546:
547: /*
548: ** Usage: sqlite3_memdebug_dump FILENAME
549: **
550: ** Write a summary of unfreed memory to FILENAME.
551: */
552: static int test_memdebug_dump(
553: void * clientData,
554: Tcl_Interp *interp,
555: int objc,
556: Tcl_Obj *CONST objv[]
557: ){
558: if( objc!=2 ){
559: Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
560: return TCL_ERROR;
561: }
562: #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
563: || defined(SQLITE_POW2_MEMORY_SIZE)
564: {
565: extern void sqlite3MemdebugDump(const char*);
566: sqlite3MemdebugDump(Tcl_GetString(objv[1]));
567: }
568: #endif
569: return TCL_OK;
570: }
571:
572: /*
573: ** Usage: sqlite3_memdebug_malloc_count
574: **
575: ** Return the total number of times malloc() has been called.
576: */
577: static int test_memdebug_malloc_count(
578: void * clientData,
579: Tcl_Interp *interp,
580: int objc,
581: Tcl_Obj *CONST objv[]
582: ){
583: int nMalloc = -1;
584: if( objc!=1 ){
585: Tcl_WrongNumArgs(interp, 1, objv, "");
586: return TCL_ERROR;
587: }
588: #if defined(SQLITE_MEMDEBUG)
589: {
590: extern int sqlite3MemdebugMallocCount();
591: nMalloc = sqlite3MemdebugMallocCount();
592: }
593: #endif
594: Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));
595: return TCL_OK;
596: }
597:
598:
599: /*
600: ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
601: **
602: ** where options are:
603: **
604: ** -repeat <count>
605: ** -benigncnt <varname>
606: **
607: ** Arrange for a simulated malloc() failure after COUNTER successes.
608: ** If a repeat count is specified, the fault is repeated that many
609: ** times.
610: **
611: ** Each call to this routine overrides the prior counter value.
612: ** This routine returns the number of simulated failures that have
613: ** happened since the previous call to this routine.
614: **
615: ** To disable simulated failures, use a COUNTER of -1.
616: */
617: static int test_memdebug_fail(
618: void * clientData,
619: Tcl_Interp *interp,
620: int objc,
621: Tcl_Obj *CONST objv[]
622: ){
623: int ii;
624: int iFail;
625: int nRepeat = 1;
626: Tcl_Obj *pBenignCnt = 0;
627: int nBenign;
628: int nFail = 0;
629:
630: if( objc<2 ){
631: Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");
632: return TCL_ERROR;
633: }
634: if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;
635:
636: for(ii=2; ii<objc; ii+=2){
637: int nOption;
638: char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);
639: char *zErr = 0;
640:
641: if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){
642: if( ii==(objc-1) ){
643: zErr = "option requires an argument: ";
644: }else{
645: if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){
646: return TCL_ERROR;
647: }
648: }
649: }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){
650: if( ii==(objc-1) ){
651: zErr = "option requires an argument: ";
652: }else{
653: pBenignCnt = objv[ii+1];
654: }
655: }else{
656: zErr = "unknown option: ";
657: }
658:
659: if( zErr ){
660: Tcl_AppendResult(interp, zErr, zOption, 0);
661: return TCL_ERROR;
662: }
663: }
664:
665: nBenign = faultsimBenignFailures();
666: nFail = faultsimFailures();
667: faultsimConfig(iFail, nRepeat);
668:
669: if( pBenignCnt ){
670: Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
671: }
672: Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));
673: return TCL_OK;
674: }
675:
676: /*
677: ** Usage: sqlite3_memdebug_pending
678: **
679: ** Return the number of malloc() calls that will succeed before a
680: ** simulated failure occurs. A negative return value indicates that
681: ** no malloc() failure is scheduled.
682: */
683: static int test_memdebug_pending(
684: void * clientData,
685: Tcl_Interp *interp,
686: int objc,
687: Tcl_Obj *CONST objv[]
688: ){
689: int nPending;
690: if( objc!=1 ){
691: Tcl_WrongNumArgs(interp, 1, objv, "");
692: return TCL_ERROR;
693: }
694: nPending = faultsimPending();
695: Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
696: return TCL_OK;
697: }
698:
699:
700: /*
701: ** Usage: sqlite3_memdebug_settitle TITLE
702: **
703: ** Set a title string stored with each allocation. The TITLE is
704: ** typically the name of the test that was running when the
705: ** allocation occurred. The TITLE is stored with the allocation
706: ** and can be used to figure out which tests are leaking memory.
707: **
708: ** Each title overwrite the previous.
709: */
710: static int test_memdebug_settitle(
711: void * clientData,
712: Tcl_Interp *interp,
713: int objc,
714: Tcl_Obj *CONST objv[]
715: ){
716: const char *zTitle;
717: if( objc!=2 ){
718: Tcl_WrongNumArgs(interp, 1, objv, "TITLE");
719: return TCL_ERROR;
720: }
721: zTitle = Tcl_GetString(objv[1]);
722: #ifdef SQLITE_MEMDEBUG
723: {
724: extern int sqlite3MemdebugSettitle(const char*);
725: sqlite3MemdebugSettitle(zTitle);
726: }
727: #endif
728: return TCL_OK;
729: }
730:
731: #define MALLOC_LOG_FRAMES 10
732: #define MALLOC_LOG_KEYINTS ( \
733: 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \
734: )
735: static Tcl_HashTable aMallocLog;
736: static int mallocLogEnabled = 0;
737:
738: typedef struct MallocLog MallocLog;
739: struct MallocLog {
740: int nCall;
741: int nByte;
742: };
743:
744: #ifdef SQLITE_MEMDEBUG
745: static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
746: if( mallocLogEnabled ){
747: MallocLog *pLog;
748: Tcl_HashEntry *pEntry;
749: int isNew;
750:
751: int aKey[MALLOC_LOG_KEYINTS];
752: int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
753:
754: memset(aKey, 0, nKey);
755: if( (sizeof(void*)*nFrame)<nKey ){
756: nKey = nFrame*sizeof(void*);
757: }
758: memcpy(aKey, aFrame, nKey);
759:
760: pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);
761: if( isNew ){
762: pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));
763: memset(pLog, 0, sizeof(MallocLog));
764: Tcl_SetHashValue(pEntry, (ClientData)pLog);
765: }else{
766: pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
767: }
768:
769: pLog->nCall++;
770: pLog->nByte += nByte;
771: }
772: }
773: #endif /* SQLITE_MEMDEBUG */
774:
775: static void test_memdebug_log_clear(void){
776: Tcl_HashSearch search;
777: Tcl_HashEntry *pEntry;
778: for(
779: pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
780: pEntry;
781: pEntry=Tcl_NextHashEntry(&search)
782: ){
783: MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
784: Tcl_Free((char *)pLog);
785: }
786: Tcl_DeleteHashTable(&aMallocLog);
787: Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
788: }
789:
790: static int test_memdebug_log(
791: void * clientData,
792: Tcl_Interp *interp,
793: int objc,
794: Tcl_Obj *CONST objv[]
795: ){
796: static int isInit = 0;
797: int iSub;
798:
799: static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
800: enum MB_enum {
801: MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
802: };
803:
804: if( !isInit ){
805: #ifdef SQLITE_MEMDEBUG
806: extern void sqlite3MemdebugBacktraceCallback(
807: void (*xBacktrace)(int, int, void **));
808: sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
809: #endif
810: Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
811: isInit = 1;
812: }
813:
814: if( objc<2 ){
815: Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
816: }
817: if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){
818: return TCL_ERROR;
819: }
820:
821: switch( (enum MB_enum)iSub ){
822: case MB_LOG_START:
823: mallocLogEnabled = 1;
824: break;
825: case MB_LOG_STOP:
826: mallocLogEnabled = 0;
827: break;
828: case MB_LOG_DUMP: {
829: Tcl_HashSearch search;
830: Tcl_HashEntry *pEntry;
831: Tcl_Obj *pRet = Tcl_NewObj();
832:
833: assert(sizeof(Tcl_WideInt)>=sizeof(void*));
834:
835: for(
836: pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
837: pEntry;
838: pEntry=Tcl_NextHashEntry(&search)
839: ){
840: Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
841: MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
842: Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
843: int ii;
844:
845: apElem[0] = Tcl_NewIntObj(pLog->nCall);
846: apElem[1] = Tcl_NewIntObj(pLog->nByte);
847: for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
848: apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
849: }
850:
851: Tcl_ListObjAppendElement(interp, pRet,
852: Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
853: );
854: }
855:
856: Tcl_SetObjResult(interp, pRet);
857: break;
858: }
859: case MB_LOG_CLEAR: {
860: test_memdebug_log_clear();
861: break;
862: }
863:
864: case MB_LOG_SYNC: {
865: #ifdef SQLITE_MEMDEBUG
866: extern void sqlite3MemdebugSync();
867: test_memdebug_log_clear();
868: mallocLogEnabled = 1;
869: sqlite3MemdebugSync();
870: #endif
871: break;
872: }
873: }
874:
875: return TCL_OK;
876: }
877:
878: /*
879: ** Usage: sqlite3_config_scratch SIZE N
880: **
881: ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
882: ** The buffer is static and is of limited size. N might be
883: ** adjusted downward as needed to accomodate the requested size.
884: ** The revised value of N is returned.
885: **
886: ** A negative SIZE causes the buffer pointer to be NULL.
887: */
888: static int test_config_scratch(
889: void * clientData,
890: Tcl_Interp *interp,
891: int objc,
892: Tcl_Obj *CONST objv[]
893: ){
894: int sz, N, rc;
895: Tcl_Obj *pResult;
896: static char *buf = 0;
897: if( objc!=3 ){
898: Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
899: return TCL_ERROR;
900: }
901: if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
902: if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
903: free(buf);
904: if( sz<0 ){
905: buf = 0;
906: rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, 0, 0, 0);
907: }else{
908: buf = malloc( sz*N + 1 );
909: rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
910: }
911: pResult = Tcl_NewObj();
912: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
913: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
914: Tcl_SetObjResult(interp, pResult);
915: return TCL_OK;
916: }
917:
918: /*
919: ** Usage: sqlite3_config_pagecache SIZE N
920: **
921: ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
922: ** The buffer is static and is of limited size. N might be
923: ** adjusted downward as needed to accomodate the requested size.
924: ** The revised value of N is returned.
925: **
926: ** A negative SIZE causes the buffer pointer to be NULL.
927: */
928: static int test_config_pagecache(
929: void * clientData,
930: Tcl_Interp *interp,
931: int objc,
932: Tcl_Obj *CONST objv[]
933: ){
934: int sz, N, rc;
935: Tcl_Obj *pResult;
936: static char *buf = 0;
937: if( objc!=3 ){
938: Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
939: return TCL_ERROR;
940: }
941: if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
942: if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
943: free(buf);
944: if( sz<0 ){
945: buf = 0;
946: rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, 0);
947: }else{
948: buf = malloc( sz*N );
949: rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);
950: }
951: pResult = Tcl_NewObj();
952: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
953: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
954: Tcl_SetObjResult(interp, pResult);
955: return TCL_OK;
956: }
957:
958: /*
959: ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
960: **
961: ** Set up the alternative test page cache. Install if INSTALL_FLAG is
962: ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
963: ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
964: ** which determines the chance of discarding a page when unpinned. 100
965: ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
966: ** seed.
967: */
968: static int test_alt_pcache(
969: void * clientData,
970: Tcl_Interp *interp,
971: int objc,
972: Tcl_Obj *CONST objv[]
973: ){
974: int installFlag;
975: int discardChance = 0;
976: int prngSeed = 0;
977: int highStress = 0;
978: extern void installTestPCache(int,unsigned,unsigned,unsigned);
979: if( objc<2 || objc>5 ){
980: Tcl_WrongNumArgs(interp, 1, objv,
981: "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
982: return TCL_ERROR;
983: }
984: if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;
985: if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
986: return TCL_ERROR;
987: }
988: if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
989: return TCL_ERROR;
990: }
991: if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
992: return TCL_ERROR;
993: }
994: if( discardChance<0 || discardChance>100 ){
995: Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
996: (char*)0);
997: return TCL_ERROR;
998: }
999: installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
1000: (unsigned)highStress);
1001: return TCL_OK;
1002: }
1003:
1004: /*
1005: ** Usage: sqlite3_config_memstatus BOOLEAN
1006: **
1007: ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
1008: */
1009: static int test_config_memstatus(
1010: void * clientData,
1011: Tcl_Interp *interp,
1012: int objc,
1013: Tcl_Obj *CONST objv[]
1014: ){
1015: int enable, rc;
1016: if( objc!=2 ){
1017: Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1018: return TCL_ERROR;
1019: }
1020: if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;
1021: rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);
1022: Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1023: return TCL_OK;
1024: }
1025:
1026: /*
1027: ** Usage: sqlite3_config_lookaside SIZE COUNT
1028: **
1029: */
1030: static int test_config_lookaside(
1031: void * clientData,
1032: Tcl_Interp *interp,
1033: int objc,
1034: Tcl_Obj *CONST objv[]
1035: ){
1036: int rc;
1037: int sz, cnt;
1038: Tcl_Obj *pRet;
1039: if( objc!=3 ){
1040: Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");
1041: return TCL_ERROR;
1042: }
1043: if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
1044: if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;
1045: pRet = Tcl_NewObj();
1046: Tcl_ListObjAppendElement(
1047: interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)
1048: );
1049: Tcl_ListObjAppendElement(
1050: interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)
1051: );
1052: rc = sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);
1053: Tcl_SetObjResult(interp, pRet);
1054: return TCL_OK;
1055: }
1056:
1057:
1058: /*
1059: ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
1060: **
1061: ** There are two static buffers with BUFID 1 and 2. Each static buffer
1062: ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1063: ** which will cause sqlite3_db_config() to allocate space on its own.
1064: */
1065: static int test_db_config_lookaside(
1066: void * clientData,
1067: Tcl_Interp *interp,
1068: int objc,
1069: Tcl_Obj *CONST objv[]
1070: ){
1071: int rc;
1072: int sz, cnt;
1073: sqlite3 *db;
1074: int bufid;
1075: static char azBuf[2][10000];
1076: int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1077: if( objc!=5 ){
1078: Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");
1079: return TCL_ERROR;
1080: }
1081: if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1082: if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;
1083: if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
1084: if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
1085: if( bufid==0 ){
1086: rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
1087: }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
1088: rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
1089: }else{
1090: Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);
1091: return TCL_ERROR;
1092: }
1093: Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
1094: return TCL_OK;
1095: }
1096:
1097: /*
1098: ** Usage:
1099: **
1100: ** sqlite3_config_heap NBYTE NMINALLOC
1101: */
1102: static int test_config_heap(
1103: void * clientData,
1104: Tcl_Interp *interp,
1105: int objc,
1106: Tcl_Obj *CONST objv[]
1107: ){
1108: static char *zBuf; /* Use this memory */
1109: static int szBuf; /* Bytes allocated for zBuf */
1110: int nByte; /* Size of buffer to pass to sqlite3_config() */
1111: int nMinAlloc; /* Size of minimum allocation */
1112: int rc; /* Return code of sqlite3_config() */
1113:
1114: Tcl_Obj * CONST *aArg = &objv[1];
1115: int nArg = objc-1;
1116:
1117: if( nArg!=2 ){
1118: Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
1119: return TCL_ERROR;
1120: }
1121: if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
1122: if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;
1123:
1124: if( nByte==0 ){
1125: free( zBuf );
1126: zBuf = 0;
1127: szBuf = 0;
1128: rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);
1129: }else{
1130: zBuf = realloc(zBuf, nByte);
1131: szBuf = nByte;
1132: rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
1133: }
1134:
1135: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1136: return TCL_OK;
1137: }
1138:
1139: /*
1140: ** tclcmd: sqlite3_config_error [DB]
1141: **
1142: ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1143: ** opcodes and verify that they return errors.
1144: */
1145: static int test_config_error(
1146: void * clientData,
1147: Tcl_Interp *interp,
1148: int objc,
1149: Tcl_Obj *CONST objv[]
1150: ){
1151: sqlite3 *db;
1152: int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1153:
1154: if( objc!=2 && objc!=1 ){
1155: Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
1156: return TCL_ERROR;
1157: }
1158: if( objc==2 ){
1159: if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1160: if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
1161: Tcl_AppendResult(interp,
1162: "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1163: (char*)0);
1164: return TCL_ERROR;
1165: }
1166: }else{
1167: if( sqlite3_config(99999)!=SQLITE_ERROR ){
1168: Tcl_AppendResult(interp,
1169: "sqlite3_config(99999) does not return SQLITE_ERROR",
1170: (char*)0);
1171: return TCL_ERROR;
1172: }
1173: }
1174: return TCL_OK;
1175: }
1176:
1177: /*
1178: ** tclcmd: sqlite3_config_uri BOOLEAN
1179: **
1180: ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1181: ** opcodes and verify that they return errors.
1182: */
1183: static int test_config_uri(
1184: void * clientData,
1185: Tcl_Interp *interp,
1186: int objc,
1187: Tcl_Obj *CONST objv[]
1188: ){
1189: int rc;
1190: int bOpenUri;
1191:
1192: if( objc!=2 ){
1193: Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
1194: return TCL_ERROR;
1195: }
1196: if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
1197: return TCL_ERROR;
1198: }
1199:
1200: rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
1201: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1202:
1203: return TCL_OK;
1204: }
1205:
1206: /*
1207: ** Usage:
1208: **
1209: ** sqlite3_dump_memsys3 FILENAME
1210: ** sqlite3_dump_memsys5 FILENAME
1211: **
1212: ** Write a summary of unfreed memsys3 allocations to FILENAME.
1213: */
1214: static int test_dump_memsys3(
1215: void * clientData,
1216: Tcl_Interp *interp,
1217: int objc,
1218: Tcl_Obj *CONST objv[]
1219: ){
1220: if( objc!=2 ){
1221: Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
1222: return TCL_ERROR;
1223: }
1224:
1225: switch( SQLITE_PTR_TO_INT(clientData) ){
1226: case 3: {
1227: #ifdef SQLITE_ENABLE_MEMSYS3
1228: extern void sqlite3Memsys3Dump(const char*);
1229: sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
1230: break;
1231: #endif
1232: }
1233: case 5: {
1234: #ifdef SQLITE_ENABLE_MEMSYS5
1235: extern void sqlite3Memsys5Dump(const char*);
1236: sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
1237: break;
1238: #endif
1239: }
1240: }
1241: return TCL_OK;
1242: }
1243:
1244: /*
1245: ** Usage: sqlite3_status OPCODE RESETFLAG
1246: **
1247: ** Return a list of three elements which are the sqlite3_status() return
1248: ** code, the current value, and the high-water mark value.
1249: */
1250: static int test_status(
1251: void * clientData,
1252: Tcl_Interp *interp,
1253: int objc,
1254: Tcl_Obj *CONST objv[]
1255: ){
1256: int rc, iValue, mxValue;
1257: int i, op, resetFlag;
1258: const char *zOpName;
1259: static const struct {
1260: const char *zName;
1261: int op;
1262: } aOp[] = {
1263: { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },
1264: { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },
1265: { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },
1266: { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },
1267: { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },
1268: { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },
1269: { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
1270: { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
1271: { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
1272: { "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT },
1273: };
1274: Tcl_Obj *pResult;
1275: if( objc!=3 ){
1276: Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");
1277: return TCL_ERROR;
1278: }
1279: zOpName = Tcl_GetString(objv[1]);
1280: for(i=0; i<ArraySize(aOp); i++){
1281: if( strcmp(aOp[i].zName, zOpName)==0 ){
1282: op = aOp[i].op;
1283: break;
1284: }
1285: }
1286: if( i>=ArraySize(aOp) ){
1287: if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;
1288: }
1289: if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;
1290: iValue = 0;
1291: mxValue = 0;
1292: rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);
1293: pResult = Tcl_NewObj();
1294: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1295: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1296: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1297: Tcl_SetObjResult(interp, pResult);
1298: return TCL_OK;
1299: }
1300:
1301: /*
1302: ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1303: **
1304: ** Return a list of three elements which are the sqlite3_db_status() return
1305: ** code, the current value, and the high-water mark value.
1306: */
1307: static int test_db_status(
1308: void * clientData,
1309: Tcl_Interp *interp,
1310: int objc,
1311: Tcl_Obj *CONST objv[]
1312: ){
1313: int rc, iValue, mxValue;
1314: int i, op, resetFlag;
1315: const char *zOpName;
1316: sqlite3 *db;
1317: int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
1318: static const struct {
1319: const char *zName;
1320: int op;
1321: } aOp[] = {
1322: { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
1323: { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
1324: { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },
1325: { "STMT_USED", SQLITE_DBSTATUS_STMT_USED },
1326: { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT },
1327: { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },
1328: { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },
1329: { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
1330: { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS }
1331: };
1332: Tcl_Obj *pResult;
1333: if( objc!=4 ){
1334: Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");
1335: return TCL_ERROR;
1336: }
1337: if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1338: zOpName = Tcl_GetString(objv[2]);
1339: if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;
1340: if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;
1341: for(i=0; i<ArraySize(aOp); i++){
1342: if( strcmp(aOp[i].zName, zOpName)==0 ){
1343: op = aOp[i].op;
1344: break;
1345: }
1346: }
1347: if( i>=ArraySize(aOp) ){
1348: if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
1349: }
1350: if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
1351: iValue = 0;
1352: mxValue = 0;
1353: rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);
1354: pResult = Tcl_NewObj();
1355: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
1356: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
1357: Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
1358: Tcl_SetObjResult(interp, pResult);
1359: return TCL_OK;
1360: }
1361:
1362: /*
1363: ** install_malloc_faultsim BOOLEAN
1364: */
1365: static int test_install_malloc_faultsim(
1366: void * clientData,
1367: Tcl_Interp *interp,
1368: int objc,
1369: Tcl_Obj *CONST objv[]
1370: ){
1371: int rc;
1372: int isInstall;
1373:
1374: if( objc!=2 ){
1375: Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
1376: return TCL_ERROR;
1377: }
1378: if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
1379: return TCL_ERROR;
1380: }
1381: rc = faultsimInstall(isInstall);
1382: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1383: return TCL_OK;
1384: }
1385:
1386: /*
1387: ** sqlite3_install_memsys3
1388: */
1389: static int test_install_memsys3(
1390: void * clientData,
1391: Tcl_Interp *interp,
1392: int objc,
1393: Tcl_Obj *CONST objv[]
1394: ){
1395: int rc = SQLITE_MISUSE;
1396: #ifdef SQLITE_ENABLE_MEMSYS3
1397: const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
1398: rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());
1399: #endif
1400: Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
1401: return TCL_OK;
1402: }
1403:
1404: static int test_vfs_oom_test(
1405: void * clientData,
1406: Tcl_Interp *interp,
1407: int objc,
1408: Tcl_Obj *CONST objv[]
1409: ){
1410: extern int sqlite3_memdebug_vfs_oom_test;
1411: if( objc>2 ){
1412: Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");
1413: return TCL_ERROR;
1414: }else if( objc==2 ){
1415: int iNew;
1416: if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;
1417: sqlite3_memdebug_vfs_oom_test = iNew;
1418: }
1419: Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));
1420: return TCL_OK;
1421: }
1422:
1423: /*
1424: ** Register commands with the TCL interpreter.
1425: */
1426: int Sqlitetest_malloc_Init(Tcl_Interp *interp){
1427: static struct {
1428: char *zName;
1429: Tcl_ObjCmdProc *xProc;
1430: int clientData;
1431: } aObjCmd[] = {
1432: { "sqlite3_malloc", test_malloc ,0 },
1433: { "sqlite3_realloc", test_realloc ,0 },
1434: { "sqlite3_free", test_free ,0 },
1435: { "memset", test_memset ,0 },
1436: { "memget", test_memget ,0 },
1437: { "sqlite3_memory_used", test_memory_used ,0 },
1438: { "sqlite3_memory_highwater", test_memory_highwater ,0 },
1439: { "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
1440: { "sqlite3_memdebug_dump", test_memdebug_dump ,0 },
1441: { "sqlite3_memdebug_fail", test_memdebug_fail ,0 },
1442: { "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
1443: { "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
1444: { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
1445: { "sqlite3_memdebug_log", test_memdebug_log ,0 },
1446: { "sqlite3_config_scratch", test_config_scratch ,0 },
1447: { "sqlite3_config_pagecache", test_config_pagecache ,0 },
1448: { "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
1449: { "sqlite3_status", test_status ,0 },
1450: { "sqlite3_db_status", test_db_status ,0 },
1451: { "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
1452: { "sqlite3_config_heap", test_config_heap ,0 },
1453: { "sqlite3_config_memstatus", test_config_memstatus ,0 },
1454: { "sqlite3_config_lookaside", test_config_lookaside ,0 },
1455: { "sqlite3_config_error", test_config_error ,0 },
1456: { "sqlite3_config_uri", test_config_uri ,0 },
1457: { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
1458: { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
1459: { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
1460: { "sqlite3_install_memsys3", test_install_memsys3 ,0 },
1461: { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 },
1462: };
1463: int i;
1464: for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1465: ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
1466: Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
1467: }
1468: return TCL_OK;
1469: }
1470: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>