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"
23 ** This structure is used to encapsulate the global state variables used
24 ** by malloc() fault simulation.
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 */
38 ** This routine exists as a place to set a breakpoint that will
39 ** fire on any simulated malloc() failure.
41 static void sqlite3Fault(void){
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.
50 static int faultsimStep(void){
51 if( likely(!memfault
.enable
) ){
54 if( memfault
.iCountdown
>0 ){
55 memfault
.iCountdown
--;
60 if( memfault
.isBenignMode
>0 ){
64 if( memfault
.nRepeat
<=0 ){
71 ** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
74 static void *faultsimMalloc(int n
){
76 if( !faultsimStep() ){
77 p
= memfault
.m
.xMalloc(n
);
84 ** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
87 static void *faultsimRealloc(void *pOld
, int n
){
89 if( !faultsimStep() ){
90 p
= memfault
.m
.xRealloc(pOld
, n
);
96 ** The following method calls are passed directly through to the underlying
105 static void faultsimFree(void *p
){
108 static int faultsimSize(void *p
){
109 return memfault
.m
.xSize(p
);
111 static int faultsimRoundup(int n
){
112 return memfault
.m
.xRoundup(n
);
114 static int faultsimInit(void *p
){
115 return memfault
.m
.xInit(memfault
.m
.pAppData
);
117 static void faultsimShutdown(void *p
){
118 memfault
.m
.xShutdown(memfault
.m
.pAppData
);
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
127 static void faultsimConfig(int nDelay
, int nRepeat
){
128 memfault
.iCountdown
= nDelay
;
129 memfault
.nRepeat
= nRepeat
;
130 memfault
.nBenign
= 0;
132 memfault
.enable
= nDelay
>=0;
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.
141 memfault
.isBenignMode
= 0;
145 ** Return the number of faults (both hard and benign faults) that have
146 ** occurred since the injector was last configured.
148 static int faultsimFailures(void){
149 return memfault
.nFail
;
153 ** Return the number of benign faults that have occurred since the
154 ** injector was last configured.
156 static int faultsimBenignFailures(void){
157 return memfault
.nBenign
;
161 ** Return the number of successes that will occur before the next failure.
162 ** If no failures are scheduled, return -1.
164 static int faultsimPending(void){
165 if( memfault
.enable
){
166 return memfault
.iCountdown
;
173 static void faultsimBeginBenign(void){
174 memfault
.isBenignMode
++;
176 static void faultsimEndBenign(void){
177 memfault
.isBenignMode
--;
181 ** Add or remove the fault-simulation layer using sqlite3_config(). If
182 ** the argument is non-zero, the
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 */
197 install
= (install
? 1 : 0);
198 assert(memfault
.isInstalled
==1 || memfault
.isInstalled
==0);
200 if( install
==memfault
.isInstalled
){
205 rc
= sqlite3_config(SQLITE_CONFIG_GETMALLOC
, &memfault
.m
);
206 assert(memfault
.m
.xMalloc
);
208 rc
= sqlite3_config(SQLITE_CONFIG_MALLOC
, &m
);
210 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS
,
211 faultsimBeginBenign
, faultsimEndBenign
214 sqlite3_mem_methods m
;
215 assert(memfault
.m
.xMalloc
);
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 );
224 rc
= sqlite3_config(SQLITE_CONFIG_MALLOC
, &memfault
.m
);
225 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS
, 0, 0);
229 memfault
.isInstalled
= 1;
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.
242 ** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
244 const char *sqlite3TestErrorName(int);
247 ** Transform pointers to text and back again
249 static void pointerToText(void *p
, char *z
){
250 static const char zHex
[] = "0123456789abcdef";
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
));
266 for(i
=0, k
=sizeof(p
)*2-1; i
<sizeof(p
)*2; i
++, k
--){
272 static int hexToInt(int h
){
273 if( h
>='0' && h
<='9' ){
275 }else if( h
>='a' && h
<='f' ){
281 static int textToPointer(const char *z
, void **pp
){
282 sqlite3_uint64 n
= 0;
285 for(i
=0; i
<sizeof(void*)*2 && z
[0]; i
++){
288 if( v
<0 ) return TCL_ERROR
;
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
) ){
296 memcpy(pp
, &u
, sizeof(u
));
304 ** Usage: sqlite3_malloc NBYTES
306 ** Raw test interface for sqlite3_malloc().
308 static int test_malloc(
312 Tcl_Obj
*CONST objv
[]
318 Tcl_WrongNumArgs(interp
, 1, objv
, "NBYTES");
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
);
329 ** Usage: sqlite3_realloc PRIOR NBYTES
331 ** Raw test interface for sqlite3_realloc().
333 static int test_realloc(
337 Tcl_Obj
*CONST objv
[]
343 Tcl_WrongNumArgs(interp
, 1, objv
, "PRIOR NBYTES");
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);
351 p
= sqlite3_realloc(pPrior
, (unsigned)nByte
);
352 pointerToText(p
, zOut
);
353 Tcl_AppendResult(interp
, zOut
, NULL
);
358 ** Usage: sqlite3_free PRIOR
360 ** Raw test interface for sqlite3_free().
362 static int test_free(
366 Tcl_Obj
*CONST objv
[]
370 Tcl_WrongNumArgs(interp
, 1, objv
, "PRIOR");
373 if( textToPointer(Tcl_GetString(objv
[1]), &pPrior
) ){
374 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
377 sqlite3_free(pPrior
);
382 ** These routines are in test_hexio.c
384 int sqlite3TestHexToBin(const char *, int, char *);
385 int sqlite3TestBinToHex(char*,int);
388 ** Usage: memset ADDRESS SIZE HEX
390 ** Set a chunk of memory (obtained from malloc, probably) to a
391 ** specified hex pattern.
393 static int test_memset(
397 Tcl_Obj
*CONST objv
[]
406 Tcl_WrongNumArgs(interp
, 1, objv
, "ADDRESS SIZE HEX");
409 if( textToPointer(Tcl_GetString(objv
[1]), &p
) ){
410 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
413 if( Tcl_GetIntFromObj(interp
, objv
[2], &size
) ){
417 Tcl_AppendResult(interp
, "size must be positive", (char*)0);
420 zHex
= Tcl_GetStringFromObj(objv
[3], &n
);
421 if( n
>sizeof(zBin
)*2 ) n
= sizeof(zBin
)*2;
422 n
= sqlite3TestHexToBin(zHex
, n
, zBin
);
424 Tcl_AppendResult(interp
, "no data", (char*)0);
428 for(i
=0; i
<size
; i
++){
435 ** Usage: memget ADDRESS SIZE
437 ** Return memory as hexadecimal text.
439 static int test_memget(
443 Tcl_Obj
*CONST objv
[]
451 Tcl_WrongNumArgs(interp
, 1, objv
, "ADDRESS SIZE");
454 if( textToPointer(Tcl_GetString(objv
[1]), &p
) ){
455 Tcl_AppendResult(interp
, "bad pointer: ", Tcl_GetString(objv
[1]), (char*)0);
458 if( Tcl_GetIntFromObj(interp
, objv
[2], &size
) ){
462 Tcl_AppendResult(interp
, "size must be positive", (char*)0);
467 if( size
>(sizeof(zHex
)-1)/2 ){
468 n
= (sizeof(zHex
)-1)/2;
472 memcpy(zHex
, zBin
, n
);
475 sqlite3TestBinToHex(zHex
, n
);
476 Tcl_AppendResult(interp
, zHex
, (char*)0);
482 ** Usage: sqlite3_memory_used
484 ** Raw test interface for sqlite3_memory_used().
486 static int test_memory_used(
490 Tcl_Obj
*CONST objv
[]
492 Tcl_SetObjResult(interp
, Tcl_NewWideIntObj(sqlite3_memory_used()));
497 ** Usage: sqlite3_memory_highwater ?RESETFLAG?
499 ** Raw test interface for sqlite3_memory_highwater().
501 static int test_memory_highwater(
505 Tcl_Obj
*CONST objv
[]
508 if( objc
!=1 && objc
!=2 ){
509 Tcl_WrongNumArgs(interp
, 1, objv
, "?RESET?");
513 if( Tcl_GetBooleanFromObj(interp
, objv
[1], &resetFlag
) ) return TCL_ERROR
;
515 Tcl_SetObjResult(interp
,
516 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag
)));
521 ** Usage: sqlite3_memdebug_backtrace DEPTH
523 ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
524 ** then this routine is a no-op.
526 static int test_memdebug_backtrace(
530 Tcl_Obj
*CONST objv
[]
534 Tcl_WrongNumArgs(interp
, 1, objv
, "DEPT");
537 if( Tcl_GetIntFromObj(interp
, objv
[1], &depth
) ) return TCL_ERROR
;
538 #ifdef SQLITE_MEMDEBUG
540 extern void sqlite3MemdebugBacktrace(int);
541 sqlite3MemdebugBacktrace(depth
);
548 ** Usage: sqlite3_memdebug_dump FILENAME
550 ** Write a summary of unfreed memory to FILENAME.
552 static int test_memdebug_dump(
556 Tcl_Obj
*CONST objv
[]
559 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME");
562 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \
563 || defined(SQLITE_POW2_MEMORY_SIZE)
565 extern void sqlite3MemdebugDump(const char*);
566 sqlite3MemdebugDump(Tcl_GetString(objv
[1]));
573 ** Usage: sqlite3_memdebug_malloc_count
575 ** Return the total number of times malloc() has been called.
577 static int test_memdebug_malloc_count(
581 Tcl_Obj
*CONST objv
[]
585 Tcl_WrongNumArgs(interp
, 1, objv
, "");
588 #if defined(SQLITE_MEMDEBUG)
590 extern int sqlite3MemdebugMallocCount();
591 nMalloc
= sqlite3MemdebugMallocCount();
594 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nMalloc
));
600 ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
602 ** where options are:
605 ** -benigncnt <varname>
607 ** Arrange for a simulated malloc() failure after COUNTER successes.
608 ** If a repeat count is specified, the fault is repeated that many
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.
615 ** To disable simulated failures, use a COUNTER of -1.
617 static int test_memdebug_fail(
621 Tcl_Obj
*CONST objv
[]
626 Tcl_Obj
*pBenignCnt
= 0;
631 Tcl_WrongNumArgs(interp
, 1, objv
, "COUNTER ?OPTIONS?");
634 if( Tcl_GetIntFromObj(interp
, objv
[1], &iFail
) ) return TCL_ERROR
;
636 for(ii
=2; ii
<objc
; ii
+=2){
638 char *zOption
= Tcl_GetStringFromObj(objv
[ii
], &nOption
);
641 if( nOption
>1 && strncmp(zOption
, "-repeat", nOption
)==0 ){
643 zErr
= "option requires an argument: ";
645 if( Tcl_GetIntFromObj(interp
, objv
[ii
+1], &nRepeat
) ){
649 }else if( nOption
>1 && strncmp(zOption
, "-benigncnt", nOption
)==0 ){
651 zErr
= "option requires an argument: ";
653 pBenignCnt
= objv
[ii
+1];
656 zErr
= "unknown option: ";
660 Tcl_AppendResult(interp
, zErr
, zOption
, 0);
665 nBenign
= faultsimBenignFailures();
666 nFail
= faultsimFailures();
667 faultsimConfig(iFail
, nRepeat
);
670 Tcl_ObjSetVar2(interp
, pBenignCnt
, 0, Tcl_NewIntObj(nBenign
), 0);
672 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nFail
));
677 ** Usage: sqlite3_memdebug_pending
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.
683 static int test_memdebug_pending(
687 Tcl_Obj
*CONST objv
[]
691 Tcl_WrongNumArgs(interp
, 1, objv
, "");
694 nPending
= faultsimPending();
695 Tcl_SetObjResult(interp
, Tcl_NewIntObj(nPending
));
701 ** Usage: sqlite3_memdebug_settitle TITLE
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.
708 ** Each title overwrite the previous.
710 static int test_memdebug_settitle(
714 Tcl_Obj
*CONST objv
[]
717 Tcl_WrongNumArgs(interp
, 1, objv
, "TITLE");
720 #ifdef SQLITE_MEMDEBUG
723 zTitle
= Tcl_GetString(objv
[1]);
724 extern int sqlite3MemdebugSettitle(const char*);
725 sqlite3MemdebugSettitle(zTitle
);
731 #define MALLOC_LOG_FRAMES 10
732 #define MALLOC_LOG_KEYINTS ( \
733 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \
735 static Tcl_HashTable aMallocLog
;
736 static int mallocLogEnabled
= 0;
738 typedef struct MallocLog MallocLog
;
744 #ifdef SQLITE_MEMDEBUG
745 static void test_memdebug_callback(int nByte
, int nFrame
, void **aFrame
){
746 if( mallocLogEnabled
){
748 Tcl_HashEntry
*pEntry
;
751 int aKey
[MALLOC_LOG_KEYINTS
];
752 int nKey
= sizeof(int)*MALLOC_LOG_KEYINTS
;
754 memset(aKey
, 0, nKey
);
755 if( (sizeof(void*)*nFrame
)<nKey
){
756 nKey
= nFrame
*sizeof(void*);
758 memcpy(aKey
, aFrame
, nKey
);
760 pEntry
= Tcl_CreateHashEntry(&aMallocLog
, (const char *)aKey
, &isNew
);
762 pLog
= (MallocLog
*)Tcl_Alloc(sizeof(MallocLog
));
763 memset(pLog
, 0, sizeof(MallocLog
));
764 Tcl_SetHashValue(pEntry
, (ClientData
)pLog
);
766 pLog
= (MallocLog
*)Tcl_GetHashValue(pEntry
);
770 pLog
->nByte
+= nByte
;
773 #endif /* SQLITE_MEMDEBUG */
775 static void test_memdebug_log_clear(void){
776 Tcl_HashSearch search
;
777 Tcl_HashEntry
*pEntry
;
779 pEntry
=Tcl_FirstHashEntry(&aMallocLog
, &search
);
781 pEntry
=Tcl_NextHashEntry(&search
)
783 MallocLog
*pLog
= (MallocLog
*)Tcl_GetHashValue(pEntry
);
784 Tcl_Free((char *)pLog
);
786 Tcl_DeleteHashTable(&aMallocLog
);
787 Tcl_InitHashTable(&aMallocLog
, MALLOC_LOG_KEYINTS
);
790 static int test_memdebug_log(
794 Tcl_Obj
*CONST objv
[]
796 static int isInit
= 0;
799 static const char *MB_strs
[] = { "start", "stop", "dump", "clear", "sync" };
801 MB_LOG_START
, MB_LOG_STOP
, MB_LOG_DUMP
, MB_LOG_CLEAR
, MB_LOG_SYNC
805 #ifdef SQLITE_MEMDEBUG
806 extern void sqlite3MemdebugBacktraceCallback(
807 void (*xBacktrace
)(int, int, void **));
808 sqlite3MemdebugBacktraceCallback(test_memdebug_callback
);
810 Tcl_InitHashTable(&aMallocLog
, MALLOC_LOG_KEYINTS
);
815 Tcl_WrongNumArgs(interp
, 1, objv
, "SUB-COMMAND ...");
817 if( Tcl_GetIndexFromObj(interp
, objv
[1], MB_strs
, "sub-command", 0, &iSub
) ){
821 switch( (enum MB_enum
)iSub
){
823 mallocLogEnabled
= 1;
826 mallocLogEnabled
= 0;
829 Tcl_HashSearch search
;
830 Tcl_HashEntry
*pEntry
;
831 Tcl_Obj
*pRet
= Tcl_NewObj();
833 assert(sizeof(Tcl_WideInt
)>=sizeof(void*));
836 pEntry
=Tcl_FirstHashEntry(&aMallocLog
, &search
);
838 pEntry
=Tcl_NextHashEntry(&search
)
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
);
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
]);
851 Tcl_ListObjAppendElement(interp
, pRet
,
852 Tcl_NewListObj(MALLOC_LOG_FRAMES
+2, apElem
)
856 Tcl_SetObjResult(interp
, pRet
);
860 test_memdebug_log_clear();
865 #ifdef SQLITE_MEMDEBUG
866 extern void sqlite3MemdebugSync();
867 test_memdebug_log_clear();
868 mallocLogEnabled
= 1;
869 sqlite3MemdebugSync();
879 ** Usage: sqlite3_config_scratch SIZE N
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.
886 ** A negative SIZE causes the buffer pointer to be NULL.
888 static int test_config_scratch(
892 Tcl_Obj
*CONST objv
[]
896 static char *buf
= 0;
898 Tcl_WrongNumArgs(interp
, 1, objv
, "SIZE N");
901 if( Tcl_GetIntFromObj(interp
, objv
[1], &sz
) ) return TCL_ERROR
;
902 if( Tcl_GetIntFromObj(interp
, objv
[2], &N
) ) return TCL_ERROR
;
906 rc
= sqlite3_config(SQLITE_CONFIG_SCRATCH
, 0, 0, 0);
908 buf
= malloc( sz
*N
+ 1 );
909 rc
= sqlite3_config(SQLITE_CONFIG_SCRATCH
, buf
, sz
, N
);
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
);
919 ** Usage: sqlite3_config_pagecache SIZE N
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.
926 ** A negative SIZE causes the buffer pointer to be NULL.
928 static int test_config_pagecache(
932 Tcl_Obj
*CONST objv
[]
936 static char *buf
= 0;
938 Tcl_WrongNumArgs(interp
, 1, objv
, "SIZE N");
941 if( Tcl_GetIntFromObj(interp
, objv
[1], &sz
) ) return TCL_ERROR
;
942 if( Tcl_GetIntFromObj(interp
, objv
[2], &N
) ) return TCL_ERROR
;
946 rc
= sqlite3_config(SQLITE_CONFIG_PAGECACHE
, 0, 0, 0);
948 buf
= malloc( sz
*N
);
949 rc
= sqlite3_config(SQLITE_CONFIG_PAGECACHE
, buf
, sz
, N
);
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
);
959 ** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
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
968 static int test_alt_pcache(
972 Tcl_Obj
*CONST objv
[]
975 int discardChance
= 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");
984 if( Tcl_GetIntFromObj(interp
, objv
[1], &installFlag
) ) return TCL_ERROR
;
985 if( objc
>=3 && Tcl_GetIntFromObj(interp
, objv
[2], &discardChance
) ){
988 if( objc
>=4 && Tcl_GetIntFromObj(interp
, objv
[3], &prngSeed
) ){
991 if( objc
>=5 && Tcl_GetIntFromObj(interp
, objv
[4], &highStress
) ){
994 if( discardChance
<0 || discardChance
>100 ){
995 Tcl_AppendResult(interp
, "discard-chance should be between 0 and 100",
999 installTestPCache(installFlag
, (unsigned)discardChance
, (unsigned)prngSeed
,
1000 (unsigned)highStress
);
1005 ** Usage: sqlite3_config_memstatus BOOLEAN
1007 ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
1009 static int test_config_memstatus(
1013 Tcl_Obj
*CONST objv
[]
1017 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOLEAN");
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
));
1027 ** Usage: sqlite3_config_lookaside SIZE COUNT
1030 static int test_config_lookaside(
1034 Tcl_Obj
*CONST objv
[]
1039 Tcl_WrongNumArgs(interp
, 1, objv
, "SIZE COUNT");
1042 if( Tcl_GetIntFromObj(interp
, objv
[1], &sz
) ) return TCL_ERROR
;
1043 if( Tcl_GetIntFromObj(interp
, objv
[2], &cnt
) ) return TCL_ERROR
;
1044 pRet
= Tcl_NewObj();
1045 Tcl_ListObjAppendElement(
1046 interp
, pRet
, Tcl_NewIntObj(sqlite3GlobalConfig
.szLookaside
)
1048 Tcl_ListObjAppendElement(
1049 interp
, pRet
, Tcl_NewIntObj(sqlite3GlobalConfig
.nLookaside
)
1051 sqlite3_config(SQLITE_CONFIG_LOOKASIDE
, sz
, cnt
);
1052 Tcl_SetObjResult(interp
, pRet
);
1058 ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
1060 ** There are two static buffers with BUFID 1 and 2. Each static buffer
1061 ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
1062 ** which will cause sqlite3_db_config() to allocate space on its own.
1064 static int test_db_config_lookaside(
1068 Tcl_Obj
*CONST objv
[]
1074 static char azBuf
[2][10000];
1075 int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
1077 Tcl_WrongNumArgs(interp
, 1, objv
, "BUFID SIZE COUNT");
1080 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
1081 if( Tcl_GetIntFromObj(interp
, objv
[2], &bufid
) ) return TCL_ERROR
;
1082 if( Tcl_GetIntFromObj(interp
, objv
[3], &sz
) ) return TCL_ERROR
;
1083 if( Tcl_GetIntFromObj(interp
, objv
[4], &cnt
) ) return TCL_ERROR
;
1085 rc
= sqlite3_db_config(db
, SQLITE_DBCONFIG_LOOKASIDE
, 0, sz
, cnt
);
1086 }else if( bufid
>=1 && bufid
<=2 && sz
*cnt
<=sizeof(azBuf
[0]) ){
1087 rc
= sqlite3_db_config(db
, SQLITE_DBCONFIG_LOOKASIDE
, azBuf
[bufid
], sz
,cnt
);
1089 Tcl_AppendResult(interp
, "illegal arguments - see documentation", (char*)0);
1092 Tcl_SetObjResult(interp
, Tcl_NewIntObj(rc
));
1099 ** sqlite3_config_heap NBYTE NMINALLOC
1101 static int test_config_heap(
1105 Tcl_Obj
*CONST objv
[]
1107 static char *zBuf
; /* Use this memory */
1108 int nByte
; /* Size of buffer to pass to sqlite3_config() */
1109 int nMinAlloc
; /* Size of minimum allocation */
1110 int rc
; /* Return code of sqlite3_config() */
1112 Tcl_Obj
* CONST
*aArg
= &objv
[1];
1116 Tcl_WrongNumArgs(interp
, 1, objv
, "NBYTE NMINALLOC");
1119 if( Tcl_GetIntFromObj(interp
, aArg
[0], &nByte
) ) return TCL_ERROR
;
1120 if( Tcl_GetIntFromObj(interp
, aArg
[1], &nMinAlloc
) ) return TCL_ERROR
;
1125 rc
= sqlite3_config(SQLITE_CONFIG_HEAP
, (void*)0, 0, 0);
1127 zBuf
= realloc(zBuf
, nByte
);
1128 rc
= sqlite3_config(SQLITE_CONFIG_HEAP
, zBuf
, nByte
, nMinAlloc
);
1131 Tcl_SetResult(interp
, (char *)sqlite3TestErrorName(rc
), TCL_VOLATILE
);
1136 ** tclcmd: sqlite3_config_error [DB]
1138 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1139 ** opcodes and verify that they return errors.
1141 static int test_config_error(
1145 Tcl_Obj
*CONST objv
[]
1148 int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
1150 if( objc
!=2 && objc
!=1 ){
1151 Tcl_WrongNumArgs(interp
, 1, objv
, "[DB]");
1155 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
1156 if( sqlite3_db_config(db
, 99999)!=SQLITE_ERROR
){
1157 Tcl_AppendResult(interp
,
1158 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
1163 if( sqlite3_config(99999)!=SQLITE_ERROR
){
1164 Tcl_AppendResult(interp
,
1165 "sqlite3_config(99999) does not return SQLITE_ERROR",
1174 ** tclcmd: sqlite3_config_uri BOOLEAN
1176 ** Invoke sqlite3_config() or sqlite3_db_config() with invalid
1177 ** opcodes and verify that they return errors.
1179 static int test_config_uri(
1183 Tcl_Obj
*CONST objv
[]
1189 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOL");
1192 if( Tcl_GetBooleanFromObj(interp
, objv
[1], &bOpenUri
) ){
1196 rc
= sqlite3_config(SQLITE_CONFIG_URI
, bOpenUri
);
1197 Tcl_SetResult(interp
, (char *)sqlite3TestErrorName(rc
), TCL_VOLATILE
);
1205 ** sqlite3_dump_memsys3 FILENAME
1206 ** sqlite3_dump_memsys5 FILENAME
1208 ** Write a summary of unfreed memsys3 allocations to FILENAME.
1210 static int test_dump_memsys3(
1214 Tcl_Obj
*CONST objv
[]
1217 Tcl_WrongNumArgs(interp
, 1, objv
, "FILENAME");
1221 switch( SQLITE_PTR_TO_INT(clientData
) ){
1223 #ifdef SQLITE_ENABLE_MEMSYS3
1224 extern void sqlite3Memsys3Dump(const char*);
1225 sqlite3Memsys3Dump(Tcl_GetString(objv
[1]));
1230 #ifdef SQLITE_ENABLE_MEMSYS5
1231 extern void sqlite3Memsys5Dump(const char*);
1232 sqlite3Memsys5Dump(Tcl_GetString(objv
[1]));
1241 ** Usage: sqlite3_status OPCODE RESETFLAG
1243 ** Return a list of three elements which are the sqlite3_status() return
1244 ** code, the current value, and the high-water mark value.
1246 static int test_status(
1250 Tcl_Obj
*CONST objv
[]
1252 int rc
, iValue
, mxValue
;
1253 int i
, op
, resetFlag
;
1254 const char *zOpName
;
1255 static const struct {
1259 { "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED
},
1260 { "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE
},
1261 { "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED
},
1262 { "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW
},
1263 { "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE
},
1264 { "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED
},
1265 { "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW
},
1266 { "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE
},
1267 { "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK
},
1268 { "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT
},
1272 Tcl_WrongNumArgs(interp
, 1, objv
, "PARAMETER RESETFLAG");
1275 zOpName
= Tcl_GetString(objv
[1]);
1276 for(i
=0; i
<ArraySize(aOp
); i
++){
1277 if( strcmp(aOp
[i
].zName
, zOpName
)==0 ){
1282 if( i
>=ArraySize(aOp
) ){
1283 if( Tcl_GetIntFromObj(interp
, objv
[1], &op
) ) return TCL_ERROR
;
1285 if( Tcl_GetBooleanFromObj(interp
, objv
[2], &resetFlag
) ) return TCL_ERROR
;
1288 rc
= sqlite3_status(op
, &iValue
, &mxValue
, resetFlag
);
1289 pResult
= Tcl_NewObj();
1290 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(rc
));
1291 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(iValue
));
1292 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(mxValue
));
1293 Tcl_SetObjResult(interp
, pResult
);
1298 ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
1300 ** Return a list of three elements which are the sqlite3_db_status() return
1301 ** code, the current value, and the high-water mark value.
1303 static int test_db_status(
1307 Tcl_Obj
*CONST objv
[]
1309 int rc
, iValue
, mxValue
;
1310 int i
, op
, resetFlag
;
1311 const char *zOpName
;
1313 int getDbPointer(Tcl_Interp
*, const char*, sqlite3
**);
1314 static const struct {
1318 { "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED
},
1319 { "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED
},
1320 { "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED
},
1321 { "STMT_USED", SQLITE_DBSTATUS_STMT_USED
},
1322 { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT
},
1323 { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
},
1324 { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
},
1325 { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT
},
1326 { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS
},
1327 { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE
}
1331 Tcl_WrongNumArgs(interp
, 1, objv
, "DB PARAMETER RESETFLAG");
1334 if( getDbPointer(interp
, Tcl_GetString(objv
[1]), &db
) ) return TCL_ERROR
;
1335 zOpName
= Tcl_GetString(objv
[2]);
1336 if( memcmp(zOpName
, "SQLITE_", 7)==0 ) zOpName
+= 7;
1337 if( memcmp(zOpName
, "DBSTATUS_", 9)==0 ) zOpName
+= 9;
1338 for(i
=0; i
<ArraySize(aOp
); i
++){
1339 if( strcmp(aOp
[i
].zName
, zOpName
)==0 ){
1344 if( i
>=ArraySize(aOp
) ){
1345 if( Tcl_GetIntFromObj(interp
, objv
[2], &op
) ) return TCL_ERROR
;
1347 if( Tcl_GetBooleanFromObj(interp
, objv
[3], &resetFlag
) ) return TCL_ERROR
;
1350 rc
= sqlite3_db_status(db
, op
, &iValue
, &mxValue
, resetFlag
);
1351 pResult
= Tcl_NewObj();
1352 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(rc
));
1353 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(iValue
));
1354 Tcl_ListObjAppendElement(0, pResult
, Tcl_NewIntObj(mxValue
));
1355 Tcl_SetObjResult(interp
, pResult
);
1360 ** install_malloc_faultsim BOOLEAN
1362 static int test_install_malloc_faultsim(
1366 Tcl_Obj
*CONST objv
[]
1372 Tcl_WrongNumArgs(interp
, 1, objv
, "BOOLEAN");
1375 if( TCL_OK
!=Tcl_GetBooleanFromObj(interp
, objv
[1], &isInstall
) ){
1378 rc
= faultsimInstall(isInstall
);
1379 Tcl_SetResult(interp
, (char *)sqlite3TestErrorName(rc
), TCL_VOLATILE
);
1384 ** sqlite3_install_memsys3
1386 static int test_install_memsys3(
1390 Tcl_Obj
*CONST objv
[]
1392 int rc
= SQLITE_MISUSE
;
1393 #ifdef SQLITE_ENABLE_MEMSYS3
1394 const sqlite3_mem_methods
*sqlite3MemGetMemsys3(void);
1395 rc
= sqlite3_config(SQLITE_CONFIG_MALLOC
, sqlite3MemGetMemsys3());
1397 Tcl_SetResult(interp
, (char *)sqlite3TestErrorName(rc
), TCL_VOLATILE
);
1401 static int test_vfs_oom_test(
1405 Tcl_Obj
*CONST objv
[]
1407 extern int sqlite3_memdebug_vfs_oom_test
;
1409 Tcl_WrongNumArgs(interp
, 1, objv
, "?INTEGER?");
1411 }else if( objc
==2 ){
1413 if( Tcl_GetIntFromObj(interp
, objv
[1], &iNew
) ) return TCL_ERROR
;
1414 sqlite3_memdebug_vfs_oom_test
= iNew
;
1416 Tcl_SetObjResult(interp
, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test
));
1421 ** Register commands with the TCL interpreter.
1423 int Sqlitetest_malloc_Init(Tcl_Interp
*interp
){
1426 Tcl_ObjCmdProc
*xProc
;
1429 { "sqlite3_malloc", test_malloc
,0 },
1430 { "sqlite3_realloc", test_realloc
,0 },
1431 { "sqlite3_free", test_free
,0 },
1432 { "memset", test_memset
,0 },
1433 { "memget", test_memget
,0 },
1434 { "sqlite3_memory_used", test_memory_used
,0 },
1435 { "sqlite3_memory_highwater", test_memory_highwater
,0 },
1436 { "sqlite3_memdebug_backtrace", test_memdebug_backtrace
,0 },
1437 { "sqlite3_memdebug_dump", test_memdebug_dump
,0 },
1438 { "sqlite3_memdebug_fail", test_memdebug_fail
,0 },
1439 { "sqlite3_memdebug_pending", test_memdebug_pending
,0 },
1440 { "sqlite3_memdebug_settitle", test_memdebug_settitle
,0 },
1441 { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count
,0 },
1442 { "sqlite3_memdebug_log", test_memdebug_log
,0 },
1443 { "sqlite3_config_scratch", test_config_scratch
,0 },
1444 { "sqlite3_config_pagecache", test_config_pagecache
,0 },
1445 { "sqlite3_config_alt_pcache", test_alt_pcache
,0 },
1446 { "sqlite3_status", test_status
,0 },
1447 { "sqlite3_db_status", test_db_status
,0 },
1448 { "install_malloc_faultsim", test_install_malloc_faultsim
,0 },
1449 { "sqlite3_config_heap", test_config_heap
,0 },
1450 { "sqlite3_config_memstatus", test_config_memstatus
,0 },
1451 { "sqlite3_config_lookaside", test_config_lookaside
,0 },
1452 { "sqlite3_config_error", test_config_error
,0 },
1453 { "sqlite3_config_uri", test_config_uri
,0 },
1454 { "sqlite3_db_config_lookaside",test_db_config_lookaside
,0 },
1455 { "sqlite3_dump_memsys3", test_dump_memsys3
,3 },
1456 { "sqlite3_dump_memsys5", test_dump_memsys3
,5 },
1457 { "sqlite3_install_memsys3", test_install_memsys3
,0 },
1458 { "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test
,0 },
1461 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
1462 ClientData c
= (ClientData
)SQLITE_INT_TO_PTR(aObjCmd
[i
].clientData
);
1463 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, c
, 0);