4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 *************************************************************************
13 ** This file contains code used to implement test interfaces to the
14 ** memory allocation subsystem.
16 #include "sqliteInt.h"
17 #if defined(INCLUDE_SQLITE_TCL_H)
18 # include "sqlite_tcl.h"
27 ** This structure is used to encapsulate the global state variables used
28 ** by malloc() fault simulation.
30 static struct MemFault
{
31 int iCountdown
; /* Number of pending successes before a failure */
32 int nRepeat
; /* Number of times to repeat the failure */
33 int nBenign
; /* Number of benign failures seen since last config */
34 int nFail
; /* Number of failures seen since last config */
35 int nOkBefore
; /* Successful allocations prior to the first fault */
36 int nOkAfter
; /* Successful allocations after a fault */
37 u8 enable
; /* True if enabled */
38 int isInstalled
; /* True if the fault simulation layer is installed */
39 int isBenignMode
; /* True if malloc failures are considered benign */
40 sqlite3_mem_methods m
; /* 'Real' malloc implementation */
44 ** This routine exists as a place to set a breakpoint that will
45 ** fire on any simulated malloc() failure.
47 static void sqlite3Fault(void){
53 ** This routine exists as a place to set a breakpoint that will
54 ** fire the first time any malloc() fails on a single test case.
55 ** The sqlite3Fault() routine above runs on every malloc() failure.
56 ** This routine only runs on the first such failure.
58 static void sqlite3FirstFault(void){
64 ** Check to see if a fault should be simulated. Return true to simulate
65 ** the fault. Return false if the fault should not be simulated.
67 static int faultsimStep(void){
68 if( likely(!memfault
.enable
) ){
72 if( memfault
.iCountdown
>0 ){
73 memfault
.iCountdown
--;
77 if( memfault
.nFail
==0 ) sqlite3FirstFault();
80 if( memfault
.isBenignMode
>0 ){
84 if( memfault
.nRepeat
<=0 ){
91 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
94 static void *faultsimMalloc(int n
){
96 if( !faultsimStep() ){
97 p
= memfault
.m
.xMalloc(n
);
104 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
107 static void *faultsimRealloc(void *pOld
, int n
){
109 if( !faultsimStep() ){
110 p
= memfault
.m
.xRealloc(pOld
, n
);
116 ** This routine configures the malloc failure simulation. After
117 ** calling this routine, the next nDelay mallocs will succeed, followed
118 ** by a block of nRepeat failures, after which malloc() calls will begin
121 static void faultsimConfig(int nDelay
, int nRepeat
){
122 memfault
.iCountdown
= nDelay
;
123 memfault
.nRepeat
= nRepeat
;
124 memfault
.nBenign
= 0;
126 memfault
.nOkBefore
= 0;
127 memfault
.nOkAfter
= 0;
128 memfault
.enable
= nDelay
>=0;
130 /* Sometimes, when running multi-threaded tests, the isBenignMode
131 ** variable is not properly incremented/decremented so that it is
132 ** 0 when not inside a benign malloc block. This doesn't affect
133 ** the multi-threaded tests, as they do not use this system. But
134 ** it does affect OOM tests run later in the same process. So
135 ** zero the variable here, just to be sure.
137 memfault
.isBenignMode
= 0;
141 ** Return the number of faults (both hard and benign faults) that have
142 ** occurred since the injector was last configured.
144 static int faultsimFailures(void){
145 return memfault
.nFail
;
149 ** Return the number of benign faults that have occurred since the
150 ** injector was last configured.
152 static int faultsimBenignFailures(void){
153 return memfault
.nBenign
;
157 ** Return the number of successes that will occur before the next failure.
158 ** If no failures are scheduled, return -1.
160 static int faultsimPending(void){
161 if( memfault
.enable
){
162 return memfault
.iCountdown
;
169 static void faultsimBeginBenign(void){
170 memfault
.isBenignMode
++;
172 static void faultsimEndBenign(void){
173 memfault
.isBenignMode
--;
177 ** Add or remove the fault-simulation layer using sqlite3_config(). If
178 ** the argument is non-zero, the
180 static int faultsimInstall(int install
){
183 install
= (install
? 1 : 0);
184 assert(memfault
.isInstalled
==1 || memfault
.isInstalled
==0);
186 if( install
==memfault
.isInstalled
){
191 rc
= sqlite3_config(SQLITE_CONFIG_GETMALLOC
, &memfault
.m
);
192 assert(memfault
.m
.xMalloc
);
194 sqlite3_mem_methods m
= memfault
.m
;
195 m
.xMalloc
= faultsimMalloc
;
196 m
.xRealloc
= faultsimRealloc
;
197 rc
= sqlite3_config(SQLITE_CONFIG_MALLOC
, &m
);
199 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS
,
200 faultsimBeginBenign
, faultsimEndBenign
203 sqlite3_mem_methods m2
;
204 assert(memfault
.m
.xMalloc
);
206 /* One should be able to reset the default memory allocator by storing
207 ** a zeroed allocator then calling GETMALLOC. */
208 memset(&m2
, 0, sizeof(m2
));
209 sqlite3_config(SQLITE_CONFIG_MALLOC
, &m2
);
210 sqlite3_config(SQLITE_CONFIG_GETMALLOC
, &m2
);
211 assert( memcmp(&m2
, &memfault
.m
, sizeof(m2
))==0 );
213 rc
= sqlite3_config(SQLITE_CONFIG_MALLOC
, &memfault
.m
);
214 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS
,
219 memfault
.isInstalled
= 1;
227 ** This function is implemented in main.c. Returns a pointer to a static
228 ** buffer containing the symbolic SQLite error code that corresponds to
229 ** the least-significant 8-bits of the integer passed as an argument.
232 ** sqlite3ErrName(1) -> "SQLITE_ERROR"
234 extern const char *sqlite3ErrName(int);
237 ** Transform pointers to text and back again
239 static void pointerToText(void *p
, char *z
){
240 static const char zHex
[] = "0123456789abcdef";
248 if( sizeof(n
)==sizeof(p
) ){
249 memcpy(&n
, &p
, sizeof(p
));
250 }else if( sizeof(u
)==sizeof(p
) ){
251 memcpy(&u
, &p
, sizeof(u
));
256 for(i
=0, k
=sizeof(p
)*2-1; i
<sizeof(p
)*2; i
++, k
--){
262 static int hexToInt(int h
){
263 if( h
>='0' && h
<='9' ){
265 }else if( h
>='a' && h
<='f' ){
271 static int textToPointer(const char *z
, void **pp
){
272 sqlite3_uint64 n
= 0;
275 for(i
=0; i
<sizeof(void*)*2 && z
[0]; i
++){
278 if( v
<0 ) return TCL_ERROR
;
281 if( *z
!=0 ) return TCL_ERROR
;
282 if( sizeof(n
)==sizeof(*pp
) ){
283 memcpy(pp
, &n
, sizeof(n
));
284 }else if( sizeof(u
)==sizeof(*pp
) ){
286 memcpy(pp
, &u
, sizeof(u
));
294 ** Usage: sqlite3_malloc NBYTES
296 ** Raw test interface for sqlite3_malloc().
298 static int SQLITE_TCLAPI
test_malloc(
302 Tcl_Obj
*CONST objv
[]
308 Tcl_WrongNumArgs(interp
, 1, objv
, "NBYTES");
311 if( Tcl_GetIntFromObj(interp
, objv
[1], &nByte
) ) return TCL_ERROR
;
312 p
= sqlite3_malloc((unsigned)nByte
);
313 pointerToText(p
, zOut
);
314 Tcl_AppendResult(interp
, zOut
, NULL
);
319 ** Usage: sqlite3_realloc PRIOR NBYTES
321 ** Raw test interface for sqlite3_realloc().
323 static int SQLITE_TCLAPI
test_realloc(
327 Tcl_Obj
*CONST objv
[]
333 Tcl_WrongNumArgs(interp
, 1, objv
, "PRIOR NBYTES");
336 if( Tcl_GetIntFromObj(interp
, objv
[2], &nByte
) ) return TCL_ERROR
;
337 if( textToPointer(Tcl_GetString(objv
[1]), &pPrior
) ){
338 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
341 p
= sqlite3_realloc(pPrior
, (unsigned)nByte
);
342 pointerToText(p
, zOut
);
343 Tcl_AppendResult(interp
, zOut
, NULL
);
348 ** Usage: sqlite3_free PRIOR
350 ** Raw test interface for sqlite3_free().
352 static int SQLITE_TCLAPI
test_free(
356 Tcl_Obj
*CONST objv
[]
360 Tcl_WrongNumArgs(interp
, 1, objv
, "PRIOR");
363 if( textToPointer(Tcl_GetString(objv
[1]), &pPrior
) ){
364 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
367 sqlite3_free(pPrior
);
372 ** These routines are in test_hexio.c
374 int sqlite3TestHexToBin(const char *, int, char *);
375 int sqlite3TestBinToHex(char*,int);
378 ** Usage: memset ADDRESS SIZE HEX
380 ** Set a chunk of memory (obtained from malloc, probably) to a
381 ** specified hex pattern.
383 static int SQLITE_TCLAPI
test_memset(
387 Tcl_Obj
*CONST objv
[]
396 Tcl_WrongNumArgs(interp
, 1, objv
, "ADDRESS SIZE HEX");
399 if( textToPointer(Tcl_GetString(objv
[1]), &p
) ){
400 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
403 if( Tcl_GetIntFromObj(interp
, objv
[2], &size
) ){
407 Tcl_AppendResult(interp
, "size must be positive", (char*)0);
410 zHex
= Tcl_GetStringFromObj(objv
[3], &n
);
411 if( n
>sizeof(zBin
)*2 ) n
= sizeof(zBin
)*2;
412 n
= sqlite3TestHexToBin(zHex
, n
, zBin
);
414 Tcl_AppendResult(interp
, "no data", (char*)0);
418 for(i
=0; i
<size
; i
++){
425 ** Usage: memget ADDRESS SIZE
427 ** Return memory as hexadecimal text.
429 static int SQLITE_TCLAPI
test_memget(
433 Tcl_Obj
*CONST objv
[]
441 Tcl_WrongNumArgs(interp
, 1, objv
, "ADDRESS SIZE");
444 if( textToPointer(Tcl_GetString(objv
[1]), &p
) ){
445 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
448 if( Tcl_GetIntFromObj(interp
, objv
[2], &size
) ){
452 Tcl_AppendResult(interp
, "size must be positive", (char*)0);
457 if( size
>(sizeof(zHex
)-1)/2 ){
458 n
= (sizeof(zHex
)-1)/2;
462 memcpy(zHex
, zBin
, n
);
465 sqlite3TestBinToHex(zHex
, n
);
466 Tcl_AppendResult(interp
, zHex
, (char*)0);
472 ** Usage: sqlite3_memory_used
474 ** Raw test interface for sqlite3_memory_used().
476 static int SQLITE_TCLAPI
test_memory_used(
480 Tcl_Obj
*CONST objv
[]
482 Tcl_SetObjResult(interp
, Tcl_NewWideIntObj(sqlite3_memory_used()));
487 ** Usage: sqlite3_memory_highwater ?RESETFLAG?
489 ** Raw test interface for sqlite3_memory_highwater().
491 static int SQLITE_TCLAPI
test_memory_highwater(
495 Tcl_Obj
*CONST objv
[]
498 if( objc
!=1 && objc
!=2 ){
499 Tcl_WrongNumArgs(interp
, 1, objv
, "?RESET?");
503 if( Tcl_GetBooleanFromObj(interp
, objv
[1], &resetFlag
) ) return TCL_ERROR
;
505 Tcl_SetObjResult(interp
,
506 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag
)));
511 ** Usage: sqlite3_memdebug_backtrace DEPTH
513 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
514 ** then this routine is a no-op.
516 static int SQLITE_TCLAPI
test_memdebug_backtrace(
520 Tcl_Obj
*CONST objv
[]
524 Tcl_WrongNumArgs(interp
, 1, objv
, "DEPT");
527 if( Tcl_GetIntFromObj(interp
, objv
[1], &depth
) ) return TCL_ERROR
;
528 #ifdef SQLITE_MEMDEBUG
530 extern void sqlite3MemdebugBacktrace(int);
531 sqlite3MemdebugBacktrace(depth
);
538 ** Usage: sqlite3_memdebug_dump FILENAME
540 ** Write a summary of unfreed memory to FILENAME.
542 static int SQLITE_TCLAPI
test_memdebug_dump(
546 Tcl_Obj
*CONST objv
[]
549 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME");
552 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
553 || defined(SQLITE_POW2_MEMORY_SIZE)
555 extern void sqlite3MemdebugDump(const char*);
556 sqlite3MemdebugDump(Tcl_GetString(objv
[1]));
563 ** Usage: sqlite3_memdebug_malloc_count
565 ** Return the total number of times malloc() has been called.
567 static int SQLITE_TCLAPI
test_memdebug_malloc_count(
571 Tcl_Obj
*CONST objv
[]
575 Tcl_WrongNumArgs(interp
, 1, objv
, "");
578 #if defined(SQLITE_MEMDEBUG)
580 extern int sqlite3MemdebugMallocCount();
581 nMalloc
= sqlite3MemdebugMallocCount();
584 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nMalloc
));
590 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
592 ** where options are:
595 ** -benigncnt <varname>
597 ** Arrange for a simulated malloc() failure after COUNTER successes.
598 ** If a repeat count is specified, the fault is repeated that many
601 ** Each call to this routine overrides the prior counter value.
602 ** This routine returns the number of simulated failures that have
603 ** happened since the previous call to this routine.
605 ** To disable simulated failures, use a COUNTER of -1.
607 static int SQLITE_TCLAPI
test_memdebug_fail(
611 Tcl_Obj
*CONST objv
[]
616 Tcl_Obj
*pBenignCnt
= 0;
621 Tcl_WrongNumArgs(interp
, 1, objv
, "COUNTER ?OPTIONS?");
624 if( Tcl_GetIntFromObj(interp
, objv
[1], &iFail
) ) return TCL_ERROR
;
626 for(ii
=2; ii
<objc
; ii
+=2){
628 char *zOption
= Tcl_GetStringFromObj(objv
[ii
], &nOption
);
631 if( nOption
>1 && strncmp(zOption
, "-repeat", nOption
)==0 ){
633 zErr
= "option requires an argument: ";
635 if( Tcl_GetIntFromObj(interp
, objv
[ii
+1], &nRepeat
) ){
639 }else if( nOption
>1 && strncmp(zOption
, "-benigncnt", nOption
)==0 ){
641 zErr
= "option requires an argument: ";
643 pBenignCnt
= objv
[ii
+1];
646 zErr
= "unknown option: ";
650 Tcl_AppendResult(interp
, zErr
, zOption
, 0);
655 nBenign
= faultsimBenignFailures();
656 nFail
= faultsimFailures();
657 faultsimConfig(iFail
, nRepeat
);
660 Tcl_ObjSetVar2(interp
, pBenignCnt
, 0, Tcl_NewIntObj(nBenign
), 0);
662 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nFail
));
667 ** Usage: sqlite3_memdebug_pending
669 ** Return the number of malloc() calls that will succeed before a
670 ** simulated failure occurs. A negative return value indicates that
671 ** no malloc() failure is scheduled.
673 static int SQLITE_TCLAPI
test_memdebug_pending(
677 Tcl_Obj
*CONST objv
[]
681 Tcl_WrongNumArgs(interp
, 1, objv
, "");
684 nPending
= faultsimPending();
685 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nPending
));
690 ** The following global variable keeps track of the number of tests
691 ** that have run. This variable is only useful when running in the
694 static int sqlite3_memdebug_title_count
= 0;
697 ** Usage: sqlite3_memdebug_settitle TITLE
699 ** Set a title string stored with each allocation. The TITLE is
700 ** typically the name of the test that was running when the
701 ** allocation occurred. The TITLE is stored with the allocation
702 ** and can be used to figure out which tests are leaking memory.
704 ** Each title overwrite the previous.
706 static int SQLITE_TCLAPI
test_memdebug_settitle(
710 Tcl_Obj
*CONST objv
[]
712 sqlite3_memdebug_title_count
++;
714 Tcl_WrongNumArgs(interp
, 1, objv
, "TITLE");
717 #ifdef SQLITE_MEMDEBUG
720 extern int sqlite3MemdebugSettitle(const char*);
721 zTitle
= Tcl_GetString(objv
[1]);
722 sqlite3MemdebugSettitle(zTitle
);
728 #define MALLOC_LOG_FRAMES 10
729 #define MALLOC_LOG_KEYINTS ( \
730 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \
732 static Tcl_HashTable aMallocLog
;
733 static int mallocLogEnabled
= 0;
735 typedef struct MallocLog MallocLog
;
741 #ifdef SQLITE_MEMDEBUG
742 static void test_memdebug_callback(int nByte
, int nFrame
, void **aFrame
){
743 if( mallocLogEnabled
){
745 Tcl_HashEntry
*pEntry
;
748 int aKey
[MALLOC_LOG_KEYINTS
];
749 unsigned int nKey
= sizeof(int)*MALLOC_LOG_KEYINTS
;
751 memset(aKey
, 0, nKey
);
752 if( (sizeof(void*)*nFrame
)<nKey
){
753 nKey
= nFrame
*sizeof(void*);
755 memcpy(aKey
, aFrame
, nKey
);
757 pEntry
= Tcl_CreateHashEntry(&aMallocLog
, (const char *)aKey
, &isNew
);
759 pLog
= (MallocLog
*)Tcl_Alloc(sizeof(MallocLog
));
760 memset(pLog
, 0, sizeof(MallocLog
));
761 Tcl_SetHashValue(pEntry
, (ClientData
)pLog
);
763 pLog
= (MallocLog
*)Tcl_GetHashValue(pEntry
);
767 pLog
->nByte
+= nByte
;
770 #endif /* SQLITE_MEMDEBUG */
772 static void test_memdebug_log_clear(void){
773 Tcl_HashSearch search
;
774 Tcl_HashEntry
*pEntry
;
776 pEntry
=Tcl_FirstHashEntry(&aMallocLog
, &search
);
778 pEntry
=Tcl_NextHashEntry(&search
)
780 MallocLog
*pLog
= (MallocLog
*)Tcl_GetHashValue(pEntry
);
781 Tcl_Free((char *)pLog
);
783 Tcl_DeleteHashTable(&aMallocLog
);
784 Tcl_InitHashTable(&aMallocLog
, MALLOC_LOG_KEYINTS
);
787 static int SQLITE_TCLAPI
test_memdebug_log(
791 Tcl_Obj
*CONST objv
[]
793 static int isInit
= 0;
796 static const char *MB_strs
[] = { "start", "stop", "dump", "clear", "sync" };
798 MB_LOG_START
, MB_LOG_STOP
, MB_LOG_DUMP
, MB_LOG_CLEAR
, MB_LOG_SYNC
802 #ifdef SQLITE_MEMDEBUG
803 extern void sqlite3MemdebugBacktraceCallback(
804 void (*xBacktrace
)(int, int, void **));
805 sqlite3MemdebugBacktraceCallback(test_memdebug_callback
);
807 Tcl_InitHashTable(&aMallocLog
, MALLOC_LOG_KEYINTS
);
812 Tcl_WrongNumArgs(interp
, 1, objv
, "SUB-COMMAND ...");
814 if( Tcl_GetIndexFromObj(interp
, objv
[1], MB_strs
, "sub-command", 0, &iSub
) ){
818 switch( (enum MB_enum
)iSub
){
820 mallocLogEnabled
= 1;
823 mallocLogEnabled
= 0;
826 Tcl_HashSearch search
;
827 Tcl_HashEntry
*pEntry
;
828 Tcl_Obj
*pRet
= Tcl_NewObj();
830 assert(sizeof(Tcl_WideInt
)>=sizeof(void*));
833 pEntry
=Tcl_FirstHashEntry(&aMallocLog
, &search
);
835 pEntry
=Tcl_NextHashEntry(&search
)
837 Tcl_Obj
*apElem
[MALLOC_LOG_FRAMES
+2];
838 MallocLog
*pLog
= (MallocLog
*)Tcl_GetHashValue(pEntry
);
839 Tcl_WideInt
*aKey
= (Tcl_WideInt
*)Tcl_GetHashKey(&aMallocLog
, pEntry
);
842 apElem
[0] = Tcl_NewIntObj(pLog
->nCall
);
843 apElem
[1] = Tcl_NewIntObj(pLog
->nByte
);
844 for(ii
=0; ii
<MALLOC_LOG_FRAMES
; ii
++){
845 apElem
[ii
+2] = Tcl_NewWideIntObj(aKey
[ii
]);
848 Tcl_ListObjAppendElement(interp
, pRet
,
849 Tcl_NewListObj(MALLOC_LOG_FRAMES
+2, apElem
)
853 Tcl_SetObjResult(interp
, pRet
);
857 test_memdebug_log_clear();
862 #ifdef SQLITE_MEMDEBUG
863 extern void sqlite3MemdebugSync();
864 test_memdebug_log_clear();
865 mallocLogEnabled
= 1;
866 sqlite3MemdebugSync();
876 ** Usage: sqlite3_config_pagecache SIZE N
878 ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
879 ** The buffer is static and is of limited size. N might be
880 ** adjusted downward as needed to accommodate the requested size.
881 ** The revised value of N is returned.
883 ** A negative SIZE causes the buffer pointer to be NULL.
885 static int SQLITE_TCLAPI
test_config_pagecache(
889 Tcl_Obj
*CONST objv
[]
893 static char *buf
= 0;
895 Tcl_WrongNumArgs(interp
, 1, objv
, "SIZE N");
898 if( Tcl_GetIntFromObj(interp
, objv
[1], &sz
) ) return TCL_ERROR
;
899 if( Tcl_GetIntFromObj(interp
, objv
[2], &N
) ) return TCL_ERROR
;
903 /* Set the return value */
905 Tcl_ListObjAppendElement(0, pRes
, Tcl_NewIntObj(sqlite3GlobalConfig
.szPage
));
906 Tcl_ListObjAppendElement(0, pRes
, Tcl_NewIntObj(sqlite3GlobalConfig
.nPage
));
907 Tcl_SetObjResult(interp
, pRes
);
910 sqlite3_config(SQLITE_CONFIG_PAGECACHE
, (void*)0, 0, 0);
912 buf
= malloc( sz
*N
);
913 sqlite3_config(SQLITE_CONFIG_PAGECACHE
, buf
, sz
, N
);
919 ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
921 ** Set up the alternative test page cache. Install if INSTALL_FLAG is
922 ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
923 ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
924 ** which determines the chance of discarding a page when unpinned. 100
925 ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
928 static int SQLITE_TCLAPI
test_alt_pcache(
932 Tcl_Obj
*CONST objv
[]
935 int discardChance
= 0;
938 extern void installTestPCache(int,unsigned,unsigned,unsigned);
939 if( objc
<2 || objc
>5 ){
940 Tcl_WrongNumArgs(interp
, 1, objv
,
941 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
944 if( Tcl_GetIntFromObj(interp
, objv
[1], &installFlag
) ) return TCL_ERROR
;
945 if( objc
>=3 && Tcl_GetIntFromObj(interp
, objv
[2], &discardChance
) ){
948 if( objc
>=4 && Tcl_GetIntFromObj(interp
, objv
[3], &prngSeed
) ){
951 if( objc
>=5 && Tcl_GetIntFromObj(interp
, objv
[4], &highStress
) ){
954 if( discardChance
<0 || discardChance
>100 ){
955 Tcl_AppendResult(interp
, "discard-chance should be between 0 and 100",
959 installTestPCache(installFlag
, (unsigned)discardChance
, (unsigned)prngSeed
,
960 (unsigned)highStress
);
965 ** Usage: sqlite3_config_memstatus BOOLEAN
967 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
969 static int SQLITE_TCLAPI
test_config_memstatus(
973 Tcl_Obj
*CONST objv
[]
977 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOLEAN");
980 if( Tcl_GetBooleanFromObj(interp
, objv
[1], &enable
) ) return TCL_ERROR
;
981 rc
= sqlite3_config(SQLITE_CONFIG_MEMSTATUS
, enable
);
982 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
987 ** Usage: sqlite3_config_lookaside SIZE COUNT
990 static int SQLITE_TCLAPI
test_config_lookaside(
994 Tcl_Obj
*CONST objv
[]
999 Tcl_WrongNumArgs(interp
, 1, objv
, "SIZE COUNT");
1002 if( Tcl_GetIntFromObj(interp
, objv
[1], &sz
) ) return TCL_ERROR
;
1003 if( Tcl_GetIntFromObj(interp
, objv
[2], &cnt
) ) return TCL_ERROR
;
1004 pRet
= Tcl_NewObj();
1005 Tcl_ListObjAppendElement(
1006 interp
, pRet
, Tcl_NewIntObj(sqlite3GlobalConfig
.szLookaside
)
1008 Tcl_ListObjAppendElement(
1009 interp
, pRet
, Tcl_NewIntObj(sqlite3GlobalConfig
.nLookaside
)
1011 sqlite3_config(SQLITE_CONFIG_LOOKASIDE
, sz
, cnt
);
1012 Tcl_SetObjResult(interp
, pRet
);
1018 ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
1020 ** There are two static buffers with BUFID 1 and 2. Each static buffer
1021 ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1022 ** which will cause sqlite3_db_config() to allocate space on its own.
1024 static int SQLITE_TCLAPI
test_db_config_lookaside(
1028 Tcl_Obj
*CONST objv
[]
1034 static char azBuf
[2][10000];
1035 extern int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
1037 Tcl_WrongNumArgs(interp
, 1, objv
, "BUFID SIZE COUNT");
1040 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
1041 if( Tcl_GetIntFromObj(interp
, objv
[2], &bufid
) ) return TCL_ERROR
;
1042 if( Tcl_GetIntFromObj(interp
, objv
[3], &sz
) ) return TCL_ERROR
;
1043 if( Tcl_GetIntFromObj(interp
, objv
[4], &cnt
) ) return TCL_ERROR
;
1045 rc
= sqlite3_db_config(db
, SQLITE_DBCONFIG_LOOKASIDE
, (void*)0, sz
, cnt
);
1046 }else if( bufid
>=1 && bufid
<=2 && sz
*cnt
<=sizeof(azBuf
[0]) ){
1047 rc
= sqlite3_db_config(db
, SQLITE_DBCONFIG_LOOKASIDE
, azBuf
[bufid
], sz
,cnt
);
1049 Tcl_AppendResult(interp
, "illegal arguments - see documentation", (char*)0);
1052 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
1057 ** Usage: sqlite3_config_heap NBYTE NMINALLOC
1059 static int SQLITE_TCLAPI
test_config_heap(
1063 Tcl_Obj
*CONST objv
[]
1065 static char *zBuf
; /* Use this memory */
1066 int nByte
; /* Size of buffer to pass to sqlite3_config() */
1067 int nMinAlloc
; /* Size of minimum allocation */
1068 int rc
; /* Return code of sqlite3_config() */
1070 Tcl_Obj
* CONST
*aArg
= &objv
[1];
1074 Tcl_WrongNumArgs(interp
, 1, objv
, "NBYTE NMINALLOC");
1077 if( Tcl_GetIntFromObj(interp
, aArg
[0], &nByte
) ) return TCL_ERROR
;
1078 if( Tcl_GetIntFromObj(interp
, aArg
[1], &nMinAlloc
) ) return TCL_ERROR
;
1083 rc
= sqlite3_config(SQLITE_CONFIG_HEAP
, (void*)0, 0, 0);
1085 zBuf
= realloc(zBuf
, nByte
);
1086 rc
= sqlite3_config(SQLITE_CONFIG_HEAP
, zBuf
, nByte
, nMinAlloc
);
1089 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1094 ** Usage: sqlite3_config_heap_size NBYTE
1096 static int SQLITE_TCLAPI
test_config_heap_size(
1100 Tcl_Obj
*CONST objv
[]
1102 int nByte
; /* Size to pass to sqlite3_config() */
1103 int rc
; /* Return code of sqlite3_config() */
1105 Tcl_Obj
* CONST
*aArg
= &objv
[1];
1109 Tcl_WrongNumArgs(interp
, 1, objv
, "NBYTE");
1112 if( Tcl_GetIntFromObj(interp
, aArg
[0], &nByte
) ) return TCL_ERROR
;
1114 rc
= sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE
, nByte
);
1116 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1121 ** Usage: sqlite3_config_error [DB]
1123 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1124 ** opcodes and verify that they return errors.
1126 static int SQLITE_TCLAPI
test_config_error(
1130 Tcl_Obj
*CONST objv
[]
1133 extern int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
1135 if( objc
!=2 && objc
!=1 ){
1136 Tcl_WrongNumArgs(interp
, 1, objv
, "[DB]");
1140 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
1141 if( sqlite3_db_config(db
, 99999)!=SQLITE_ERROR
){
1142 Tcl_AppendResult(interp
,
1143 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1148 if( sqlite3_config(99999)!=SQLITE_ERROR
){
1149 Tcl_AppendResult(interp
,
1150 "sqlite3_config(99999) does not return SQLITE_ERROR",
1159 ** Usage: sqlite3_config_uri BOOLEAN
1161 ** Enables or disables interpretation of URI parameters by default using
1162 ** SQLITE_CONFIG_URI.
1164 static int SQLITE_TCLAPI
test_config_uri(
1168 Tcl_Obj
*CONST objv
[]
1174 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOL");
1177 if( Tcl_GetBooleanFromObj(interp
, objv
[1], &bOpenUri
) ){
1181 rc
= sqlite3_config(SQLITE_CONFIG_URI
, bOpenUri
);
1182 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1188 ** Usage: sqlite3_config_cis BOOLEAN
1190 ** Enables or disables the use of the covering-index scan optimization.
1191 ** SQLITE_CONFIG_COVERING_INDEX_SCAN.
1193 static int SQLITE_TCLAPI
test_config_cis(
1197 Tcl_Obj
*CONST objv
[]
1203 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOL");
1206 if( Tcl_GetBooleanFromObj(interp
, objv
[1], &bUseCis
) ){
1210 rc
= sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN
, bUseCis
);
1211 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1217 ** Usage: sqlite3_config_pmasz INTEGER
1219 ** Set the minimum PMA size.
1221 static int SQLITE_TCLAPI
test_config_pmasz(
1225 Tcl_Obj
*CONST objv
[]
1231 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOL");
1234 if( Tcl_GetIntFromObj(interp
, objv
[1], &iPmaSz
) ){
1238 rc
= sqlite3_config(SQLITE_CONFIG_PMASZ
, iPmaSz
);
1239 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1246 ** Usage: sqlite3_dump_memsys3 FILENAME
1247 ** sqlite3_dump_memsys5 FILENAME
1249 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1251 static int SQLITE_TCLAPI
test_dump_memsys3(
1255 Tcl_Obj
*CONST objv
[]
1258 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME");
1262 switch( SQLITE_PTR_TO_INT(clientData
) ){
1264 #ifdef SQLITE_ENABLE_MEMSYS3
1265 extern void sqlite3Memsys3Dump(const char*);
1266 sqlite3Memsys3Dump(Tcl_GetString(objv
[1]));
1271 #ifdef SQLITE_ENABLE_MEMSYS5
1272 extern void sqlite3Memsys5Dump(const char*);
1273 sqlite3Memsys5Dump(Tcl_GetString(objv
[1]));
1282 ** Usage: sqlite3_status OPCODE RESETFLAG
1284 ** Return a list of three elements which are the sqlite3_status() return
1285 ** code, the current value, and the high-water mark value.
1287 static int SQLITE_TCLAPI
test_status(
1291 Tcl_Obj
*CONST objv
[]
1293 int rc
, iValue
, mxValue
;
1294 int i
, op
= 0, resetFlag
;
1295 const char *zOpName
;
1296 static const struct {
1300 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED
},
1301 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE
},
1302 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED
},
1303 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW
},
1304 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE
},
1305 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED
},
1306 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW
},
1307 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE
},
1308 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK
},
1309 { "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT
},
1313 Tcl_WrongNumArgs(interp
, 1, objv
, "PARAMETER RESETFLAG");
1316 zOpName
= Tcl_GetString(objv
[1]);
1317 for(i
=0; i
<ArraySize(aOp
); i
++){
1318 if( strcmp(aOp
[i
].zName
, zOpName
)==0 ){
1323 if( i
>=ArraySize(aOp
) ){
1324 if( Tcl_GetIntFromObj(interp
, objv
[1], &op
) ) return TCL_ERROR
;
1326 if( Tcl_GetBooleanFromObj(interp
, objv
[2], &resetFlag
) ) return TCL_ERROR
;
1329 rc
= sqlite3_status(op
, &iValue
, &mxValue
, resetFlag
);
1330 pResult
= Tcl_NewObj();
1331 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(rc
));
1332 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(iValue
));
1333 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(mxValue
));
1334 Tcl_SetObjResult(interp
, pResult
);
1339 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1341 ** Return a list of three elements which are the sqlite3_db_status() return
1342 ** code, the current value, and the high-water mark value.
1344 static int SQLITE_TCLAPI
test_db_status(
1348 Tcl_Obj
*CONST objv
[]
1350 int rc
, iValue
, mxValue
;
1351 int i
, op
= 0, resetFlag
;
1352 const char *zOpName
;
1354 extern int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
1355 static const struct {
1359 { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED
},
1360 { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED
},
1361 { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED
},
1362 { "STMT_USED", SQLITE_DBSTATUS_STMT_USED
},
1363 { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT
},
1364 { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
},
1365 { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
},
1366 { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT
},
1367 { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS
},
1368 { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE
},
1369 { "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS
},
1370 { "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED
},
1371 { "CACHE_SPILL", SQLITE_DBSTATUS_CACHE_SPILL
},
1375 Tcl_WrongNumArgs(interp
, 1, objv
, "DB PARAMETER RESETFLAG");
1378 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
1379 zOpName
= Tcl_GetString(objv
[2]);
1380 if( memcmp(zOpName
, "SQLITE_", 7)==0 ) zOpName
+= 7;
1381 if( memcmp(zOpName
, "DBSTATUS_", 9)==0 ) zOpName
+= 9;
1382 for(i
=0; i
<ArraySize(aOp
); i
++){
1383 if( strcmp(aOp
[i
].zName
, zOpName
)==0 ){
1388 if( i
>=ArraySize(aOp
) ){
1389 if( Tcl_GetIntFromObj(interp
, objv
[2], &op
) ) return TCL_ERROR
;
1391 if( Tcl_GetBooleanFromObj(interp
, objv
[3], &resetFlag
) ) return TCL_ERROR
;
1394 rc
= sqlite3_db_status(db
, op
, &iValue
, &mxValue
, resetFlag
);
1395 pResult
= Tcl_NewObj();
1396 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(rc
));
1397 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(iValue
));
1398 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(mxValue
));
1399 Tcl_SetObjResult(interp
, pResult
);
1404 ** install_malloc_faultsim BOOLEAN
1406 static int SQLITE_TCLAPI
test_install_malloc_faultsim(
1410 Tcl_Obj
*CONST objv
[]
1416 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOLEAN");
1419 if( TCL_OK
!=Tcl_GetBooleanFromObj(interp
, objv
[1], &isInstall
) ){
1422 rc
= faultsimInstall(isInstall
);
1423 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1428 ** sqlite3_install_memsys3
1430 static int SQLITE_TCLAPI
test_install_memsys3(
1434 Tcl_Obj
*CONST objv
[]
1436 int rc
= SQLITE_MISUSE
;
1437 #ifdef SQLITE_ENABLE_MEMSYS3
1438 const sqlite3_mem_methods
*sqlite3MemGetMemsys3(void);
1439 rc
= sqlite3_config(SQLITE_CONFIG_MALLOC
, sqlite3MemGetMemsys3());
1441 Tcl_SetResult(interp
, (char *)sqlite3ErrName(rc
), TCL_VOLATILE
);
1445 static int SQLITE_TCLAPI
test_vfs_oom_test(
1449 Tcl_Obj
*CONST objv
[]
1451 extern int sqlite3_memdebug_vfs_oom_test
;
1453 Tcl_WrongNumArgs(interp
, 1, objv
, "?INTEGER?");
1455 }else if( objc
==2 ){
1457 if( Tcl_GetIntFromObj(interp
, objv
[1], &iNew
) ) return TCL_ERROR
;
1458 sqlite3_memdebug_vfs_oom_test
= iNew
;
1460 Tcl_SetObjResult(interp
, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test
));
1465 ** Register commands with the TCL interpreter.
1467 int Sqlitetest_malloc_Init(Tcl_Interp
*interp
){
1470 Tcl_ObjCmdProc
*xProc
;
1473 { "sqlite3_malloc", test_malloc
,0 },
1474 { "sqlite3_realloc", test_realloc
,0 },
1475 { "sqlite3_free", test_free
,0 },
1476 { "memset", test_memset
,0 },
1477 { "memget", test_memget
,0 },
1478 { "sqlite3_memory_used", test_memory_used
,0 },
1479 { "sqlite3_memory_highwater", test_memory_highwater
,0 },
1480 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace
,0 },
1481 { "sqlite3_memdebug_dump", test_memdebug_dump
,0 },
1482 { "sqlite3_memdebug_fail", test_memdebug_fail
,0 },
1483 { "sqlite3_memdebug_pending", test_memdebug_pending
,0 },
1484 { "sqlite3_memdebug_settitle", test_memdebug_settitle
,0 },
1485 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count
,0 },
1486 { "sqlite3_memdebug_log", test_memdebug_log
,0 },
1487 { "sqlite3_config_pagecache", test_config_pagecache
,0 },
1488 { "sqlite3_config_alt_pcache", test_alt_pcache
,0 },
1489 { "sqlite3_status", test_status
,0 },
1490 { "sqlite3_db_status", test_db_status
,0 },
1491 { "install_malloc_faultsim", test_install_malloc_faultsim
,0 },
1492 { "sqlite3_config_heap", test_config_heap
,0 },
1493 { "sqlite3_config_heap_size", test_config_heap_size
,0 },
1494 { "sqlite3_config_memstatus", test_config_memstatus
,0 },
1495 { "sqlite3_config_lookaside", test_config_lookaside
,0 },
1496 { "sqlite3_config_error", test_config_error
,0 },
1497 { "sqlite3_config_uri", test_config_uri
,0 },
1498 { "sqlite3_config_cis", test_config_cis
,0 },
1499 { "sqlite3_config_pmasz", test_config_pmasz
,0 },
1500 { "sqlite3_db_config_lookaside",test_db_config_lookaside
,0 },
1501 { "sqlite3_dump_memsys3", test_dump_memsys3
,3 },
1502 { "sqlite3_dump_memsys5", test_dump_memsys3
,5 },
1503 { "sqlite3_install_memsys3", test_install_memsys3
,0 },
1504 { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test
,0 },
1507 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
1508 ClientData c
= (ClientData
)SQLITE_INT_TO_PTR(aObjCmd
[i
].clientData
);
1509 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, c
, 0);