/*** 2007 August 15**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.******************************************************************************* This file contains code used to implement test interfaces to the** memory allocation subsystem.*/#include "sqliteInt.h"#include "tclsqlite.h"#include <stdlib.h>#include <string.h>#include <assert.h>/*** This structure is used to encapsulate the global state variables used** by malloc() fault simulation.*/static struct MemFault {int iCountdown; /* Number of pending successes before a failure */int nRepeat; /* Number of times to repeat the failure */int nBenign; /* Number of benign failures seen since last config */int nFail; /* Number of failures seen since last config */int nOkBefore; /* Successful allocations prior to the first fault */int nOkAfter; /* Successful allocations after a fault */u8 enable; /* True if enabled */int isInstalled; /* True if the fault simulation layer is installed */int isBenignMode; /* True if malloc failures are considered benign */sqlite3_mem_methods m; /* 'Real' malloc implementation */} memfault;/*** This routine exists as a place to set a breakpoint that will** fire on any simulated malloc() failure.*/static void sqlite3Fault(void){static u64 cnt = 0;cnt++;if( cnt>((u64)1<<63) ) abort();}/*** This routine exists as a place to set a breakpoint that will** fire the first time any malloc() fails on a single test case.** The sqlite3Fault() routine above runs on every malloc() failure.** This routine only runs on the first such failure.*/static void sqlite3FirstFault(void){static u64 cnt2 = 0;cnt2++;if( cnt2>((u64)1<<63) ) abort();}/*** Check to see if a fault should be simulated. Return true to simulate** the fault. Return false if the fault should not be simulated.*/static int faultsimStep(void){if( likely(!memfault.enable) ){memfault.nOkAfter++;return 0;}if( memfault.iCountdown>0 ){memfault.iCountdown--;memfault.nOkBefore++;return 0;}if( memfault.nFail==0 ) sqlite3FirstFault();sqlite3Fault();memfault.nFail++;if( memfault.isBenignMode>0 ){memfault.nBenign++;}memfault.nRepeat--;if( memfault.nRepeat<=0 ){memfault.enable = 0;}return 1;}/*** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation** logic.*/static void *faultsimMalloc(int n){void *p = 0;if( !faultsimStep() ){p = memfault.m.xMalloc(n);}return p;}/*** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation** logic.*/static void *faultsimRealloc(void *pOld, int n){void *p = 0;if( !faultsimStep() ){p = memfault.m.xRealloc(pOld, n);}return p;}/*** This routine configures the malloc failure simulation. After** calling this routine, the next nDelay mallocs will succeed, followed** by a block of nRepeat failures, after which malloc() calls will begin** to succeed again.*/static void faultsimConfig(int nDelay, int nRepeat){memfault.iCountdown = nDelay;memfault.nRepeat = nRepeat;memfault.nBenign = 0;memfault.nFail = 0;memfault.nOkBefore = 0;memfault.nOkAfter = 0;memfault.enable = nDelay>=0;/* Sometimes, when running multi-threaded tests, the isBenignMode** variable is not properly incremented/decremented so that it is** 0 when not inside a benign malloc block. This doesn't affect** the multi-threaded tests, as they do not use this system. But** it does affect OOM tests run later in the same process. So** zero the variable here, just to be sure.*/memfault.isBenignMode = 0;}/*** Return the number of faults (both hard and benign faults) that have** occurred since the injector was last configured.*/static int faultsimFailures(void){return memfault.nFail;}/*** Return the number of benign faults that have occurred since the** injector was last configured.*/static int faultsimBenignFailures(void){return memfault.nBenign;}/*** Return the number of successes that will occur before the next failure.** If no failures are scheduled, return -1.*/static int faultsimPending(void){if( memfault.enable ){return memfault.iCountdown;}else{return -1;}}static void faultsimBeginBenign(void){memfault.isBenignMode++;}static void faultsimEndBenign(void){memfault.isBenignMode--;}/*** Add or remove the fault-simulation layer using sqlite3_config(). If** the argument is non-zero, the*/static int faultsimInstall(int install){int rc;install = (install ? 1 : 0);assert(memfault.isInstalled==1 || memfault.isInstalled==0);if( install==memfault.isInstalled ){return SQLITE_ERROR;}if( install ){rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);assert(memfault.m.xMalloc);if( rc==SQLITE_OK ){sqlite3_mem_methods m = memfault.m;m.xMalloc = faultsimMalloc;m.xRealloc = faultsimRealloc;rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);}sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,faultsimBeginBenign, faultsimEndBenign);}else{sqlite3_mem_methods m2;assert(memfault.m.xMalloc);/* One should be able to reset the default memory allocator by storing** a zeroed allocator then calling GETMALLOC. */memset(&m2, 0, sizeof(m2));sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,(void*)0, (void*)0);}if( rc==SQLITE_OK ){memfault.isInstalled = 1;}return rc;}#ifdef SQLITE_TEST/*** This function is implemented in main.c. Returns a pointer to a static** buffer containing the symbolic SQLite error code that corresponds to** the least-significant 8-bits of the integer passed as an argument.** For example:**** sqlite3ErrName(1) -> "SQLITE_ERROR"*/extern const char *sqlite3ErrName(int);/*** Transform pointers to text and back again*/static void pointerToText(void *p, char *z){static const char zHex[] = "0123456789abcdef";int i, k;unsigned int u;sqlite3_uint64 n;if( p==0 ){strcpy(z, "0");return;}if( sizeof(n)==sizeof(p) ){memcpy(&n, &p, sizeof(p));}else if( sizeof(u)==sizeof(p) ){memcpy(&u, &p, sizeof(u));n = u;}else{assert( 0 );}for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){z[k] = zHex[n&0xf];n >>= 4;}z[sizeof(p)*2] = 0;}static int hexToInt(int h){if( h>='0' && h<='9' ){return h - '0';}else if( h>='a' && h<='f' ){return h - 'a' + 10;}else{return -1;}}static int textToPointer(const char *z, void **pp){sqlite3_uint64 n = 0;int i;unsigned int u;for(i=0; i<sizeof(void*)*2 && z[0]; i++){int v;v = hexToInt(*z++);if( v<0 ) return TCL_ERROR;n = n*16 + v;}if( *z!=0 ) return TCL_ERROR;if( sizeof(n)==sizeof(*pp) ){memcpy(pp, &n, sizeof(n));}else if( sizeof(u)==sizeof(*pp) ){u = (unsigned int)n;memcpy(pp, &u, sizeof(u));}else{assert( 0 );}return TCL_OK;}/*** Usage: sqlite3_malloc NBYTES**** Raw test interface for sqlite3_malloc().*/static int SQLITE_TCLAPI test_malloc(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int nByte;void *p;char zOut[100];if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;p = sqlite3_malloc((unsigned)nByte);pointerToText(p, zOut);Tcl_AppendResult(interp, zOut, NULL);return TCL_OK;}/*** Usage: sqlite3_realloc PRIOR NBYTES**** Raw test interface for sqlite3_realloc().*/static int SQLITE_TCLAPI test_realloc(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int nByte;void *pPrior, *p;char zOut[100];if( objc!=3 ){Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);return TCL_ERROR;}p = sqlite3_realloc(pPrior, (unsigned)nByte);pointerToText(p, zOut);Tcl_AppendResult(interp, zOut, NULL);return TCL_OK;}/*** Usage: sqlite3_free PRIOR**** Raw test interface for sqlite3_free().*/static int SQLITE_TCLAPI test_free(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){void *pPrior;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");return TCL_ERROR;}if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);return TCL_ERROR;}sqlite3_free(pPrior);return TCL_OK;}/*** These routines are in test_hexio.c*/int sqlite3TestHexToBin(const char *, int, char *);int sqlite3TestBinToHex(char*,int);/*** Usage: memset ADDRESS SIZE HEX**** Set a chunk of memory (obtained from malloc, probably) to a** specified hex pattern.*/static int SQLITE_TCLAPI test_memset(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){void *p;int size, i;Tcl_Size n;char *zHex;char *zOut;char zBin[100];if( objc!=4 ){Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");return TCL_ERROR;}if( textToPointer(Tcl_GetString(objv[1]), &p) ){Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[2], &size) ){return TCL_ERROR;}if( size<=0 ){Tcl_AppendResult(interp, "size must be positive", (char*)0);return TCL_ERROR;}zHex = Tcl_GetStringFromObj(objv[3], &n);if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;n = sqlite3TestHexToBin(zHex, (int)n, zBin);if( n==0 ){Tcl_AppendResult(interp, "no data", (char*)0);return TCL_ERROR;}zOut = p;for(i=0; i<size; i++){zOut[i] = zBin[i%n];}return TCL_OK;}/*** Usage: memget ADDRESS SIZE**** Return memory as hexadecimal text.*/static int SQLITE_TCLAPI test_memget(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){void *p;int size, n;char *zBin;char zHex[100];if( objc!=3 ){Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");return TCL_ERROR;}if( textToPointer(Tcl_GetString(objv[1]), &p) ){Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[2], &size) ){return TCL_ERROR;}if( size<=0 ){Tcl_AppendResult(interp, "size must be positive", (char*)0);return TCL_ERROR;}zBin = p;while( size>0 ){if( size>(sizeof(zHex)-1)/2 ){n = (sizeof(zHex)-1)/2;}else{n = size;}memcpy(zHex, zBin, n);zBin += n;size -= n;sqlite3TestBinToHex(zHex, n);Tcl_AppendResult(interp, zHex, (char*)0);}return TCL_OK;}/*** Usage: sqlite3_memory_used**** Raw test interface for sqlite3_memory_used().*/static int SQLITE_TCLAPI test_memory_used(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));return TCL_OK;}/*** Usage: sqlite3_memory_highwater ?RESETFLAG?**** Raw test interface for sqlite3_memory_highwater().*/static int SQLITE_TCLAPI test_memory_highwater(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int resetFlag = 0;if( objc!=1 && objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");return TCL_ERROR;}if( objc==2 ){if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;}Tcl_SetObjResult(interp,Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));return TCL_OK;}/*** Usage: sqlite3_memdebug_backtrace DEPTH**** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined** then this routine is a no-op.*/static int SQLITE_TCLAPI test_memdebug_backtrace(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int depth;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "DEPT");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;#ifdef SQLITE_MEMDEBUG{extern void sqlite3MemdebugBacktrace(int);sqlite3MemdebugBacktrace(depth);}#endifreturn TCL_OK;}/*** Usage: sqlite3_memdebug_dump FILENAME**** Write a summary of unfreed memory to FILENAME.*/static int SQLITE_TCLAPI test_memdebug_dump(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");return TCL_ERROR;}#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \|| defined(SQLITE_POW2_MEMORY_SIZE){extern void sqlite3MemdebugDump(const char*);sqlite3MemdebugDump(Tcl_GetString(objv[1]));}#endifreturn TCL_OK;}/*** Usage: sqlite3_memdebug_malloc_count**** Return the total number of times malloc() has been called.*/static int SQLITE_TCLAPI test_memdebug_malloc_count(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int nMalloc = -1;if( objc!=1 ){Tcl_WrongNumArgs(interp, 1, objv, "");return TCL_ERROR;}#if defined(SQLITE_MEMDEBUG){extern int sqlite3MemdebugMallocCount();nMalloc = sqlite3MemdebugMallocCount();}#endifTcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));return TCL_OK;}/*** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?**** where options are:**** -repeat <count>** -benigncnt <varname>**** Arrange for a simulated malloc() failure after COUNTER successes.** If a repeat count is specified, the fault is repeated that many** times.**** Each call to this routine overrides the prior counter value.** This routine returns the number of simulated failures that have** happened since the previous call to this routine.**** To disable simulated failures, use a COUNTER of -1.*/static int SQLITE_TCLAPI test_memdebug_fail(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int ii;int iFail;int nRepeat = 1;Tcl_Obj *pBenignCnt = 0;int nBenign;int nFail = 0;if( objc<2 ){Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;for(ii=2; ii<objc; ii+=2){Tcl_Size nOption;char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);char *zErr = 0;if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){if( ii==(objc-1) ){zErr = "option requires an argument: ";}else{if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){return TCL_ERROR;}}}else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){if( ii==(objc-1) ){zErr = "option requires an argument: ";}else{pBenignCnt = objv[ii+1];}}else{zErr = "unknown option: ";}if( zErr ){Tcl_AppendResult(interp, zErr, zOption, NULL);return TCL_ERROR;}}nBenign = faultsimBenignFailures();nFail = faultsimFailures();faultsimConfig(iFail, nRepeat);if( pBenignCnt ){Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);}Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));return TCL_OK;}/*** Usage: sqlite3_memdebug_pending**** Return the number of malloc() calls that will succeed before a** simulated failure occurs. A negative return value indicates that** no malloc() failure is scheduled.*/static int SQLITE_TCLAPI test_memdebug_pending(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int nPending;if( objc!=1 ){Tcl_WrongNumArgs(interp, 1, objv, "");return TCL_ERROR;}nPending = faultsimPending();Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));return TCL_OK;}/*** The following global variable keeps track of the number of tests** that have run. This variable is only useful when running in the** debugger.*/static int sqlite3_memdebug_title_count = 0;/*** Usage: sqlite3_memdebug_settitle TITLE**** Set a title string stored with each allocation. The TITLE is** typically the name of the test that was running when the** allocation occurred. The TITLE is stored with the allocation** and can be used to figure out which tests are leaking memory.**** Each title overwrite the previous.*/static int SQLITE_TCLAPI test_memdebug_settitle(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){sqlite3_memdebug_title_count++;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "TITLE");return TCL_ERROR;}#ifdef SQLITE_MEMDEBUG{const char *zTitle;extern int sqlite3MemdebugSettitle(const char*);zTitle = Tcl_GetString(objv[1]);sqlite3MemdebugSettitle(zTitle);}#endifreturn TCL_OK;}#define MALLOC_LOG_FRAMES 10#define MALLOC_LOG_KEYINTS ( \10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \)static Tcl_HashTable aMallocLog;static int mallocLogEnabled = 0;typedef struct MallocLog MallocLog;struct MallocLog {int nCall;int nByte;};#ifdef SQLITE_MEMDEBUGstatic void test_memdebug_callback(int nByte, int nFrame, void **aFrame){if( mallocLogEnabled ){MallocLog *pLog;Tcl_HashEntry *pEntry;int isNew;int aKey[MALLOC_LOG_KEYINTS];unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;memset(aKey, 0, nKey);if( (sizeof(void*)*nFrame)<nKey ){nKey = nFrame*sizeof(void*);}memcpy(aKey, aFrame, nKey);pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);if( isNew ){pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));memset(pLog, 0, sizeof(MallocLog));Tcl_SetHashValue(pEntry, (ClientData)pLog);}else{pLog = (MallocLog *)Tcl_GetHashValue(pEntry);}pLog->nCall++;pLog->nByte += nByte;}}#endif /* SQLITE_MEMDEBUG */static void test_memdebug_log_clear(void){Tcl_HashSearch search;Tcl_HashEntry *pEntry;for(pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);pEntry;pEntry=Tcl_NextHashEntry(&search)){MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);Tcl_Free((char *)pLog);}Tcl_DeleteHashTable(&aMallocLog);Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);}static int SQLITE_TCLAPI test_memdebug_log(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){static int isInit = 0;int iSub;static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };enum MB_enum {MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC};if( !isInit ){#ifdef SQLITE_MEMDEBUGextern void sqlite3MemdebugBacktraceCallback(void (*xBacktrace)(int, int, void **));sqlite3MemdebugBacktraceCallback(test_memdebug_callback);#endifTcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);isInit = 1;}if( objc<2 ){Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");}if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){return TCL_ERROR;}switch( (enum MB_enum)iSub ){case MB_LOG_START:mallocLogEnabled = 1;break;case MB_LOG_STOP:mallocLogEnabled = 0;break;case MB_LOG_DUMP: {Tcl_HashSearch search;Tcl_HashEntry *pEntry;Tcl_Obj *pRet = Tcl_NewObj();assert(sizeof(Tcl_WideInt)>=sizeof(void*));for(pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);pEntry;pEntry=Tcl_NextHashEntry(&search)){Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);int ii;apElem[0] = Tcl_NewIntObj(pLog->nCall);apElem[1] = Tcl_NewIntObj(pLog->nByte);for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);}Tcl_ListObjAppendElement(interp, pRet,Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem));}Tcl_SetObjResult(interp, pRet);break;}case MB_LOG_CLEAR: {test_memdebug_log_clear();break;}case MB_LOG_SYNC: {#ifdef SQLITE_MEMDEBUGextern void sqlite3MemdebugSync();test_memdebug_log_clear();mallocLogEnabled = 1;sqlite3MemdebugSync();#endifbreak;}}return TCL_OK;}/*** Usage: sqlite3_config_pagecache SIZE N**** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.** The buffer is static and is of limited size. N might be** adjusted downward as needed to accommodate the requested size.** The revised value of N is returned.**** A negative SIZE causes the buffer pointer to be NULL.*/static int SQLITE_TCLAPI test_config_pagecache(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int sz, N;Tcl_Obj *pRes;static char *buf = 0;if( objc!=3 ){Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;free(buf);buf = 0;/* Set the return value */pRes = Tcl_NewObj();Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.szPage));Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.nPage));Tcl_SetObjResult(interp, pRes);if( sz<0 ){sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, 0);}else{buf = malloc( sz*N );sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);}return TCL_OK;}/*** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED**** Set up the alternative test page cache. Install if INSTALL_FLAG is** true and uninstall (reverting to the default page cache) if INSTALL_FLAG** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive** which determines the chance of discarding a page when unpinned. 100** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator** seed.*/static int SQLITE_TCLAPI test_alt_pcache(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int installFlag;int discardChance = 0;int prngSeed = 0;int highStress = 0;extern void installTestPCache(int,unsigned,unsigned,unsigned);if( objc<2 || objc>5 ){Tcl_WrongNumArgs(interp, 1, objv,"INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){return TCL_ERROR;}if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){return TCL_ERROR;}if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){return TCL_ERROR;}if( discardChance<0 || discardChance>100 ){Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",(char*)0);return TCL_ERROR;}installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,(unsigned)highStress);return TCL_OK;}/*** Usage: sqlite3_config_memstatus BOOLEAN**** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.*/static int SQLITE_TCLAPI test_config_memstatus(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int enable, rc;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");return TCL_ERROR;}if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));return TCL_OK;}/*** Usage: sqlite3_config_lookaside SIZE COUNT***/static int SQLITE_TCLAPI test_config_lookaside(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int sz, cnt;Tcl_Obj *pRet;if( objc!=3 ){Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;pRet = Tcl_NewObj();Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside));Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside));sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);Tcl_SetObjResult(interp, pRet);return TCL_OK;}/*** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT**** There are two static buffers with BUFID 1 and 2. Each static buffer** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL** which will cause sqlite3_db_config() to allocate space on its own.*/static int SQLITE_TCLAPI test_db_config_lookaside(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc;int sz, cnt;sqlite3 *db;int bufid;static char azBuf[2][10000];extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);if( objc!=5 ){Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");return TCL_ERROR;}if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;if( bufid==0 ){rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);}else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);}else{Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);return TCL_ERROR;}Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));return TCL_OK;}/*** Usage: sqlite3_config_heap NBYTE NMINALLOC*/static int SQLITE_TCLAPI test_config_heap(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){static char *zBuf; /* Use this memory */int nByte; /* Size of buffer to pass to sqlite3_config() */int nMinAlloc; /* Size of minimum allocation */int rc; /* Return code of sqlite3_config() */Tcl_Obj * CONST *aArg = &objv[1];int nArg = objc-1;if( nArg!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;if( nByte==0 ){free( zBuf );zBuf = 0;rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);}else{zBuf = realloc(zBuf, nByte);rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);}Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}/*** Usage: sqlite3_config_heap_size NBYTE*/static int SQLITE_TCLAPI test_config_heap_size(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int nByte; /* Size to pass to sqlite3_config() */int rc; /* Return code of sqlite3_config() */Tcl_Obj * CONST *aArg = &objv[1];int nArg = objc-1;if( nArg!=1 ){Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}/*** Usage: sqlite3_config_error [DB]**** Invoke sqlite3_config() or sqlite3_db_config() with invalid** opcodes and verify that they return errors.*/static int SQLITE_TCLAPI test_config_error(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){sqlite3 *db;extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);if( objc!=2 && objc!=1 ){Tcl_WrongNumArgs(interp, 1, objv, "[DB]");return TCL_ERROR;}if( objc==2 ){if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){Tcl_AppendResult(interp,"sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",(char*)0);return TCL_ERROR;}}else{if( sqlite3_config(99999)!=SQLITE_ERROR ){Tcl_AppendResult(interp,"sqlite3_config(99999) does not return SQLITE_ERROR",(char*)0);return TCL_ERROR;}}return TCL_OK;}/*** Usage: sqlite3_config_uri BOOLEAN**** Enables or disables interpretation of URI parameters by default using** SQLITE_CONFIG_URI.*/static int SQLITE_TCLAPI test_config_uri(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc;int bOpenUri;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "BOOL");return TCL_ERROR;}if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){return TCL_ERROR;}rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}/*** Usage: sqlite3_config_cis BOOLEAN**** Enables or disables the use of the covering-index scan optimization.** SQLITE_CONFIG_COVERING_INDEX_SCAN.*/static int SQLITE_TCLAPI test_config_cis(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc;int bUseCis;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "BOOL");return TCL_ERROR;}if( Tcl_GetBooleanFromObj(interp, objv[1], &bUseCis) ){return TCL_ERROR;}rc = sqlite3_config(SQLITE_CONFIG_COVERING_INDEX_SCAN, bUseCis);Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}/*** Usage: sqlite3_config_pmasz INTEGER**** Set the minimum PMA size.*/static int SQLITE_TCLAPI test_config_pmasz(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc;int iPmaSz;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "BOOL");return TCL_ERROR;}if( Tcl_GetIntFromObj(interp, objv[1], &iPmaSz) ){return TCL_ERROR;}rc = sqlite3_config(SQLITE_CONFIG_PMASZ, iPmaSz);Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}/*** Usage: sqlite3_dump_memsys3 FILENAME** sqlite3_dump_memsys5 FILENAME**** Write a summary of unfreed memsys3 allocations to FILENAME.*/static int SQLITE_TCLAPI test_dump_memsys3(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");return TCL_ERROR;}switch( SQLITE_PTR_TO_INT(clientData) ){case 3: {#ifdef SQLITE_ENABLE_MEMSYS3extern void sqlite3Memsys3Dump(const char*);sqlite3Memsys3Dump(Tcl_GetString(objv[1]));break;#endif}case 5: {#ifdef SQLITE_ENABLE_MEMSYS5extern void sqlite3Memsys5Dump(const char*);sqlite3Memsys5Dump(Tcl_GetString(objv[1]));break;#endif}}return TCL_OK;}/*** Usage: sqlite3_status OPCODE RESETFLAG**** Return a list of three elements which are the sqlite3_status() return** code, the current value, and the high-water mark value.*/static int SQLITE_TCLAPI test_status(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc, iValue, mxValue;int i, op = 0, resetFlag;const char *zOpName;static const struct {const char *zName;int op;} aOp[] = {{ "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED },{ "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE },{ "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED },{ "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW },{ "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE },{ "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED },{ "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },{ "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },{ "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },{ "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT },};Tcl_Obj *pResult;if( objc!=3 ){Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG");return TCL_ERROR;}zOpName = Tcl_GetString(objv[1]);for(i=0; i<ArraySize(aOp); i++){if( strcmp(aOp[i].zName, zOpName)==0 ){op = aOp[i].op;break;}}if( i>=ArraySize(aOp) ){if( Tcl_GetIntFromObj(interp, objv[1], &op) ) return TCL_ERROR;}if( Tcl_GetBooleanFromObj(interp, objv[2], &resetFlag) ) return TCL_ERROR;iValue = 0;mxValue = 0;rc = sqlite3_status(op, &iValue, &mxValue, resetFlag);pResult = Tcl_NewObj();Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));Tcl_SetObjResult(interp, pResult);return TCL_OK;}/*** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG**** Return a list of three elements which are the sqlite3_db_status() return** code, the current value, and the high-water mark value.*/static int SQLITE_TCLAPI test_db_status(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc, iValue, mxValue;int i, op = 0, resetFlag;const char *zOpName;sqlite3 *db;extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);static const struct {const char *zName;int op;} aOp[] = {{ "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },{ "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },{ "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },{ "STMT_USED", SQLITE_DBSTATUS_STMT_USED },{ "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT },{ "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE },{ "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL },{ "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },{ "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS },{ "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE },{ "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS },{ "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED },{ "CACHE_SPILL", SQLITE_DBSTATUS_CACHE_SPILL },{ "TEMPBUF_SPILL", SQLITE_DBSTATUS_TEMPBUF_SPILL },};Tcl_Obj *pResult;if( objc!=4 ){Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG");return TCL_ERROR;}if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;zOpName = Tcl_GetString(objv[2]);if( memcmp(zOpName, "SQLITE_", 7)==0 ) zOpName += 7;if( memcmp(zOpName, "DBSTATUS_", 9)==0 ) zOpName += 9;for(i=0; i<ArraySize(aOp); i++){if( strcmp(aOp[i].zName, zOpName)==0 ){op = aOp[i].op;break;}}if( i>=ArraySize(aOp) ){if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;}if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;iValue = 0;mxValue = 0;rc = sqlite3_db_status(db, op, &iValue, &mxValue, resetFlag);pResult = Tcl_NewObj();Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));Tcl_SetObjResult(interp, pResult);return TCL_OK;}/*** install_malloc_faultsim BOOLEAN*/static int SQLITE_TCLAPI test_install_malloc_faultsim(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc;int isInstall;if( objc!=2 ){Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");return TCL_ERROR;}if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){return TCL_ERROR;}rc = faultsimInstall(isInstall);Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}/*** sqlite3_install_memsys3*/static int SQLITE_TCLAPI test_install_memsys3(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){int rc = SQLITE_MISUSE;#ifdef SQLITE_ENABLE_MEMSYS3const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3());#endifTcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);return TCL_OK;}static int SQLITE_TCLAPI test_vfs_oom_test(void * clientData,Tcl_Interp *interp,int objc,Tcl_Obj *CONST objv[]){extern int sqlite3_memdebug_vfs_oom_test;if( objc>2 ){Tcl_WrongNumArgs(interp, 1, objv, "?INTEGER?");return TCL_ERROR;}else if( objc==2 ){int iNew;if( Tcl_GetIntFromObj(interp, objv[1], &iNew) ) return TCL_ERROR;sqlite3_memdebug_vfs_oom_test = iNew;}Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_vfs_oom_test));return TCL_OK;}/*** Register commands with the TCL interpreter.*/int Sqlitetest_malloc_Init(Tcl_Interp *interp){static struct {char *zName;Tcl_ObjCmdProc *xProc;int clientData;} aObjCmd[] = {{ "sqlite3_malloc", test_malloc ,0 },{ "sqlite3_realloc", test_realloc ,0 },{ "sqlite3_free", test_free ,0 },{ "memset", test_memset ,0 },{ "memget", test_memget ,0 },{ "sqlite3_memory_used", test_memory_used ,0 },{ "sqlite3_memory_highwater", test_memory_highwater ,0 },{ "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },{ "sqlite3_memdebug_dump", test_memdebug_dump ,0 },{ "sqlite3_memdebug_fail", test_memdebug_fail ,0 },{ "sqlite3_memdebug_pending", test_memdebug_pending ,0 },{ "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },{ "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },{ "sqlite3_memdebug_log", test_memdebug_log ,0 },{ "sqlite3_config_pagecache", test_config_pagecache ,0 },{ "sqlite3_config_alt_pcache", test_alt_pcache ,0 },{ "sqlite3_status", test_status ,0 },{ "sqlite3_db_status", test_db_status ,0 },{ "install_malloc_faultsim", test_install_malloc_faultsim ,0 },{ "sqlite3_config_heap", test_config_heap ,0 },{ "sqlite3_config_heap_size", test_config_heap_size ,0 },{ "sqlite3_config_memstatus", test_config_memstatus ,0 },{ "sqlite3_config_lookaside", test_config_lookaside ,0 },{ "sqlite3_config_error", test_config_error ,0 },{ "sqlite3_config_uri", test_config_uri ,0 },{ "sqlite3_config_cis", test_config_cis ,0 },{ "sqlite3_config_pmasz", test_config_pmasz ,0 },{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },{ "sqlite3_install_memsys3", test_install_memsys3 ,0 },{ "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 },};int i;for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);}return TCL_OK;}#endif
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。