AryaWu/sqlite
0
1/*2** 2007 August 153**4** The author disclaims copyright to this source code. In place of5** a legal notice, here is a blessing:6**7** May you do good and not evil.8** May you find forgiveness for yourself and forgive others.9** May you share freely, never taking more than you give.10**11*************************************************************************12**13** This file contains code used to implement test interfaces to the14** memory allocation subsystem.15*/16#include "sqliteInt.h"17#include "tclsqlite.h"18#include <stdlib.h>19#include <string.h>20#include <assert.h>21 22/*23** This structure is used to encapsulate the global state variables used 24** by malloc() fault simulation.25*/26static 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 int nOkBefore; /* Successful allocations prior to the first fault */32 int nOkAfter; /* Successful allocations after a fault */33 u8 enable; /* True if enabled */34 int isInstalled; /* True if the fault simulation layer is installed */35 int isBenignMode; /* True if malloc failures are considered benign */36 sqlite3_mem_methods m; /* 'Real' malloc implementation */37} memfault;38 39/*40** This routine exists as a place to set a breakpoint that will41** fire on any simulated malloc() failure.42*/43static void sqlite3Fault(void){44 static u64 cnt = 0;45 cnt++;46 if( cnt>((u64)1<<63) ) abort();47}48 49/*50** This routine exists as a place to set a breakpoint that will51** fire the first time any malloc() fails on a single test case.52** The sqlite3Fault() routine above runs on every malloc() failure.53** This routine only runs on the first such failure.54*/55static void sqlite3FirstFault(void){56 static u64 cnt2 = 0;57 cnt2++;58 if( cnt2>((u64)1<<63) ) abort();59}60 61/*62** Check to see if a fault should be simulated. Return true to simulate63** the fault. Return false if the fault should not be simulated.64*/65static int faultsimStep(void){66 if( likely(!memfault.enable) ){67 memfault.nOkAfter++;68 return 0;69 }70 if( memfault.iCountdown>0 ){71 memfault.iCountdown--;72 memfault.nOkBefore++;73 return 0;74 }75 if( memfault.nFail==0 ) sqlite3FirstFault();76 sqlite3Fault();77 memfault.nFail++;78 if( memfault.isBenignMode>0 ){79 memfault.nBenign++;80 }81 memfault.nRepeat--;82 if( memfault.nRepeat<=0 ){83 memfault.enable = 0;84 }85 return 1; 86}87 88/*89** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation90** logic.91*/92static void *faultsimMalloc(int n){93 void *p = 0;94 if( !faultsimStep() ){95 p = memfault.m.xMalloc(n);96 }97 return p;98}99 100 101/*102** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation103** logic.104*/105static void *faultsimRealloc(void *pOld, int n){106 void *p = 0;107 if( !faultsimStep() ){108 p = memfault.m.xRealloc(pOld, n);109 }110 return p;111}112 113/*114** This routine configures the malloc failure simulation. After115** calling this routine, the next nDelay mallocs will succeed, followed116** by a block of nRepeat failures, after which malloc() calls will begin117** to succeed again.118*/119static void faultsimConfig(int nDelay, int nRepeat){120 memfault.iCountdown = nDelay;121 memfault.nRepeat = nRepeat;122 memfault.nBenign = 0;123 memfault.nFail = 0;124 memfault.nOkBefore = 0;125 memfault.nOkAfter = 0;126 memfault.enable = nDelay>=0;127 128 /* Sometimes, when running multi-threaded tests, the isBenignMode 129 ** variable is not properly incremented/decremented so that it is130 ** 0 when not inside a benign malloc block. This doesn't affect131 ** the multi-threaded tests, as they do not use this system. But132 ** it does affect OOM tests run later in the same process. So133 ** zero the variable here, just to be sure.134 */135 memfault.isBenignMode = 0;136}137 138/*139** Return the number of faults (both hard and benign faults) that have140** occurred since the injector was last configured.141*/142static int faultsimFailures(void){143 return memfault.nFail;144}145 146/*147** Return the number of benign faults that have occurred since the148** injector was last configured.149*/150static int faultsimBenignFailures(void){151 return memfault.nBenign;152}153 154/*155** Return the number of successes that will occur before the next failure.156** If no failures are scheduled, return -1.157*/158static int faultsimPending(void){159 if( memfault.enable ){160 return memfault.iCountdown;161 }else{162 return -1;163 }164}165 166 167static void faultsimBeginBenign(void){168 memfault.isBenignMode++;169}170static void faultsimEndBenign(void){171 memfault.isBenignMode--;172}173 174/*175** Add or remove the fault-simulation layer using sqlite3_config(). If176** the argument is non-zero, the 177*/178static int faultsimInstall(int install){179 int rc;180 181 install = (install ? 1 : 0);182 assert(memfault.isInstalled==1 || memfault.isInstalled==0);183 184 if( install==memfault.isInstalled ){185 return SQLITE_ERROR;186 }187 188 if( install ){189 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);190 assert(memfault.m.xMalloc);191 if( rc==SQLITE_OK ){192 sqlite3_mem_methods m = memfault.m;193 m.xMalloc = faultsimMalloc;194 m.xRealloc = faultsimRealloc;195 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);196 }197 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 198 faultsimBeginBenign, faultsimEndBenign199 );200 }else{201 sqlite3_mem_methods m2;202 assert(memfault.m.xMalloc);203 204 /* One should be able to reset the default memory allocator by storing205 ** a zeroed allocator then calling GETMALLOC. */206 memset(&m2, 0, sizeof(m2));207 sqlite3_config(SQLITE_CONFIG_MALLOC, &m2);208 sqlite3_config(SQLITE_CONFIG_GETMALLOC, &m2);209 assert( memcmp(&m2, &memfault.m, sizeof(m2))==0 );210 211 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memfault.m);212 sqlite3_test_control(SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,213 (void*)0, (void*)0);214 }215 216 if( rc==SQLITE_OK ){217 memfault.isInstalled = 1;218 }219 return rc;220}221 222#ifdef SQLITE_TEST223 224/*225** This function is implemented in main.c. Returns a pointer to a static226** buffer containing the symbolic SQLite error code that corresponds to227** the least-significant 8-bits of the integer passed as an argument.228** For example:229**230** sqlite3ErrName(1) -> "SQLITE_ERROR"231*/232extern const char *sqlite3ErrName(int);233 234/*235** Transform pointers to text and back again236*/237static void pointerToText(void *p, char *z){238 static const char zHex[] = "0123456789abcdef";239 int i, k;240 unsigned int u;241 sqlite3_uint64 n;242 if( p==0 ){243 strcpy(z, "0");244 return;245 }246 if( sizeof(n)==sizeof(p) ){247 memcpy(&n, &p, sizeof(p));248 }else if( sizeof(u)==sizeof(p) ){249 memcpy(&u, &p, sizeof(u));250 n = u;251 }else{252 assert( 0 );253 }254 for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){255 z[k] = zHex[n&0xf];256 n >>= 4;257 }258 z[sizeof(p)*2] = 0;259}260static int hexToInt(int h){261 if( h>='0' && h<='9' ){262 return h - '0';263 }else if( h>='a' && h<='f' ){264 return h - 'a' + 10;265 }else{266 return -1;267 }268}269static int textToPointer(const char *z, void **pp){270 sqlite3_uint64 n = 0;271 int i;272 unsigned int u;273 for(i=0; i<sizeof(void*)*2 && z[0]; i++){274 int v;275 v = hexToInt(*z++);276 if( v<0 ) return TCL_ERROR;277 n = n*16 + v;278 }279 if( *z!=0 ) return TCL_ERROR;280 if( sizeof(n)==sizeof(*pp) ){281 memcpy(pp, &n, sizeof(n));282 }else if( sizeof(u)==sizeof(*pp) ){283 u = (unsigned int)n;284 memcpy(pp, &u, sizeof(u));285 }else{286 assert( 0 );287 }288 return TCL_OK;289}290 291/*292** Usage: sqlite3_malloc NBYTES293**294** Raw test interface for sqlite3_malloc().295*/296static int SQLITE_TCLAPI test_malloc(297 void * clientData,298 Tcl_Interp *interp,299 int objc,300 Tcl_Obj *CONST objv[]301){302 int nByte;303 void *p;304 char zOut[100];305 if( objc!=2 ){306 Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");307 return TCL_ERROR;308 }309 if( Tcl_GetIntFromObj(interp, objv[1], &nByte) ) return TCL_ERROR;310 p = sqlite3_malloc((unsigned)nByte);311 pointerToText(p, zOut);312 Tcl_AppendResult(interp, zOut, NULL);313 return TCL_OK;314}315 316/*317** Usage: sqlite3_realloc PRIOR NBYTES318**319** Raw test interface for sqlite3_realloc().320*/321static int SQLITE_TCLAPI test_realloc(322 void * clientData,323 Tcl_Interp *interp,324 int objc,325 Tcl_Obj *CONST objv[]326){327 int nByte;328 void *pPrior, *p;329 char zOut[100];330 if( objc!=3 ){331 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");332 return TCL_ERROR;333 }334 if( Tcl_GetIntFromObj(interp, objv[2], &nByte) ) return TCL_ERROR;335 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){336 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);337 return TCL_ERROR;338 }339 p = sqlite3_realloc(pPrior, (unsigned)nByte);340 pointerToText(p, zOut);341 Tcl_AppendResult(interp, zOut, NULL);342 return TCL_OK;343}344 345/*346** Usage: sqlite3_free PRIOR347**348** Raw test interface for sqlite3_free().349*/350static int SQLITE_TCLAPI test_free(351 void * clientData,352 Tcl_Interp *interp,353 int objc,354 Tcl_Obj *CONST objv[]355){356 void *pPrior;357 if( objc!=2 ){358 Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");359 return TCL_ERROR;360 }361 if( textToPointer(Tcl_GetString(objv[1]), &pPrior) ){362 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);363 return TCL_ERROR;364 }365 sqlite3_free(pPrior);366 return TCL_OK;367}368 369/*370** These routines are in test_hexio.c371*/372int sqlite3TestHexToBin(const char *, int, char *);373int sqlite3TestBinToHex(char*,int);374 375/*376** Usage: memset ADDRESS SIZE HEX377**378** Set a chunk of memory (obtained from malloc, probably) to a379** specified hex pattern.380*/381static int SQLITE_TCLAPI test_memset(382 void * clientData,383 Tcl_Interp *interp,384 int objc,385 Tcl_Obj *CONST objv[]386){387 void *p;388 int size, i;389 Tcl_Size n;390 char *zHex;391 char *zOut;392 char zBin[100];393 394 if( objc!=4 ){395 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");396 return TCL_ERROR;397 }398 if( textToPointer(Tcl_GetString(objv[1]), &p) ){399 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);400 return TCL_ERROR;401 }402 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){403 return TCL_ERROR;404 }405 if( size<=0 ){406 Tcl_AppendResult(interp, "size must be positive", (char*)0);407 return TCL_ERROR;408 }409 zHex = Tcl_GetStringFromObj(objv[3], &n);410 if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;411 n = sqlite3TestHexToBin(zHex, (int)n, zBin);412 if( n==0 ){413 Tcl_AppendResult(interp, "no data", (char*)0);414 return TCL_ERROR;415 }416 zOut = p;417 for(i=0; i<size; i++){418 zOut[i] = zBin[i%n];419 }420 return TCL_OK;421}422 423/*424** Usage: memget ADDRESS SIZE425**426** Return memory as hexadecimal text.427*/428static int SQLITE_TCLAPI test_memget(429 void * clientData,430 Tcl_Interp *interp,431 int objc,432 Tcl_Obj *CONST objv[]433){434 void *p;435 int size, n;436 char *zBin;437 char zHex[100];438 439 if( objc!=3 ){440 Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");441 return TCL_ERROR;442 }443 if( textToPointer(Tcl_GetString(objv[1]), &p) ){444 Tcl_AppendResult(interp, "bad pointer: ", Tcl_GetString(objv[1]), (char*)0);445 return TCL_ERROR;446 }447 if( Tcl_GetIntFromObj(interp, objv[2], &size) ){448 return TCL_ERROR;449 }450 if( size<=0 ){451 Tcl_AppendResult(interp, "size must be positive", (char*)0);452 return TCL_ERROR;453 }454 zBin = p;455 while( size>0 ){456 if( size>(sizeof(zHex)-1)/2 ){457 n = (sizeof(zHex)-1)/2;458 }else{459 n = size;460 }461 memcpy(zHex, zBin, n);462 zBin += n;463 size -= n;464 sqlite3TestBinToHex(zHex, n);465 Tcl_AppendResult(interp, zHex, (char*)0);466 }467 return TCL_OK;468}469 470/*471** Usage: sqlite3_memory_used472**473** Raw test interface for sqlite3_memory_used().474*/475static int SQLITE_TCLAPI test_memory_used(476 void * clientData,477 Tcl_Interp *interp,478 int objc,479 Tcl_Obj *CONST objv[]480){481 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used()));482 return TCL_OK;483}484 485/*486** Usage: sqlite3_memory_highwater ?RESETFLAG?487**488** Raw test interface for sqlite3_memory_highwater().489*/490static int SQLITE_TCLAPI test_memory_highwater(491 void * clientData,492 Tcl_Interp *interp,493 int objc,494 Tcl_Obj *CONST objv[]495){496 int resetFlag = 0;497 if( objc!=1 && objc!=2 ){498 Tcl_WrongNumArgs(interp, 1, objv, "?RESET?");499 return TCL_ERROR;500 }501 if( objc==2 ){502 if( Tcl_GetBooleanFromObj(interp, objv[1], &resetFlag) ) return TCL_ERROR;503 } 504 Tcl_SetObjResult(interp, 505 Tcl_NewWideIntObj(sqlite3_memory_highwater(resetFlag)));506 return TCL_OK;507}508 509/*510** Usage: sqlite3_memdebug_backtrace DEPTH511**512** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined513** then this routine is a no-op.514*/515static int SQLITE_TCLAPI test_memdebug_backtrace(516 void * clientData,517 Tcl_Interp *interp,518 int objc,519 Tcl_Obj *CONST objv[]520){521 int depth;522 if( objc!=2 ){523 Tcl_WrongNumArgs(interp, 1, objv, "DEPT");524 return TCL_ERROR;525 }526 if( Tcl_GetIntFromObj(interp, objv[1], &depth) ) return TCL_ERROR;527#ifdef SQLITE_MEMDEBUG528 {529 extern void sqlite3MemdebugBacktrace(int);530 sqlite3MemdebugBacktrace(depth);531 }532#endif533 return TCL_OK;534}535 536/*537** Usage: sqlite3_memdebug_dump FILENAME538**539** Write a summary of unfreed memory to FILENAME.540*/541static int SQLITE_TCLAPI test_memdebug_dump(542 void * clientData,543 Tcl_Interp *interp,544 int objc,545 Tcl_Obj *CONST objv[]546){547 if( objc!=2 ){548 Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");549 return TCL_ERROR;550 }551#if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE) \552 || defined(SQLITE_POW2_MEMORY_SIZE)553 {554 extern void sqlite3MemdebugDump(const char*);555 sqlite3MemdebugDump(Tcl_GetString(objv[1]));556 }557#endif558 return TCL_OK;559}560 561/*562** Usage: sqlite3_memdebug_malloc_count563**564** Return the total number of times malloc() has been called.565*/566static int SQLITE_TCLAPI test_memdebug_malloc_count(567 void * clientData,568 Tcl_Interp *interp,569 int objc,570 Tcl_Obj *CONST objv[]571){572 int nMalloc = -1;573 if( objc!=1 ){574 Tcl_WrongNumArgs(interp, 1, objv, "");575 return TCL_ERROR;576 }577#if defined(SQLITE_MEMDEBUG)578 {579 extern int sqlite3MemdebugMallocCount();580 nMalloc = sqlite3MemdebugMallocCount();581 }582#endif583 Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc));584 return TCL_OK;585}586 587 588/*589** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?590**591** where options are:592**593** -repeat <count>594** -benigncnt <varname>595**596** Arrange for a simulated malloc() failure after COUNTER successes.597** If a repeat count is specified, the fault is repeated that many598** times.599**600** Each call to this routine overrides the prior counter value.601** This routine returns the number of simulated failures that have602** happened since the previous call to this routine.603**604** To disable simulated failures, use a COUNTER of -1.605*/606static int SQLITE_TCLAPI test_memdebug_fail(607 void * clientData,608 Tcl_Interp *interp,609 int objc,610 Tcl_Obj *CONST objv[]611){612 int ii;613 int iFail;614 int nRepeat = 1;615 Tcl_Obj *pBenignCnt = 0;616 int nBenign;617 int nFail = 0;618 619 if( objc<2 ){620 Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?OPTIONS?");621 return TCL_ERROR;622 }623 if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR;624 625 for(ii=2; ii<objc; ii+=2){626 Tcl_Size nOption;627 char *zOption = Tcl_GetStringFromObj(objv[ii], &nOption);628 char *zErr = 0;629 630 if( nOption>1 && strncmp(zOption, "-repeat", nOption)==0 ){631 if( ii==(objc-1) ){632 zErr = "option requires an argument: ";633 }else{634 if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){635 return TCL_ERROR;636 }637 }638 }else if( nOption>1 && strncmp(zOption, "-benigncnt", nOption)==0 ){639 if( ii==(objc-1) ){640 zErr = "option requires an argument: ";641 }else{642 pBenignCnt = objv[ii+1];643 }644 }else{645 zErr = "unknown option: ";646 }647 648 if( zErr ){649 Tcl_AppendResult(interp, zErr, zOption, NULL);650 return TCL_ERROR;651 }652 }653 654 nBenign = faultsimBenignFailures();655 nFail = faultsimFailures();656 faultsimConfig(iFail, nRepeat);657 658 if( pBenignCnt ){659 Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);660 }661 Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail));662 return TCL_OK;663}664 665/*666** Usage: sqlite3_memdebug_pending667**668** Return the number of malloc() calls that will succeed before a 669** simulated failure occurs. A negative return value indicates that670** no malloc() failure is scheduled.671*/672static int SQLITE_TCLAPI test_memdebug_pending(673 void * clientData,674 Tcl_Interp *interp,675 int objc,676 Tcl_Obj *CONST objv[]677){678 int nPending;679 if( objc!=1 ){680 Tcl_WrongNumArgs(interp, 1, objv, "");681 return TCL_ERROR;682 }683 nPending = faultsimPending();684 Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));685 return TCL_OK;686}687 688/*689** The following global variable keeps track of the number of tests690** that have run. This variable is only useful when running in the691** debugger.692*/693static int sqlite3_memdebug_title_count = 0;694 695/*696** Usage: sqlite3_memdebug_settitle TITLE697**698** Set a title string stored with each allocation. The TITLE is699** typically the name of the test that was running when the700** allocation occurred. The TITLE is stored with the allocation701** and can be used to figure out which tests are leaking memory.702**703** Each title overwrite the previous.704*/705static int SQLITE_TCLAPI test_memdebug_settitle(706 void * clientData,707 Tcl_Interp *interp,708 int objc,709 Tcl_Obj *CONST objv[]710){711 sqlite3_memdebug_title_count++;712 if( objc!=2 ){713 Tcl_WrongNumArgs(interp, 1, objv, "TITLE");714 return TCL_ERROR;715 }716#ifdef SQLITE_MEMDEBUG717 {718 const char *zTitle;719 extern int sqlite3MemdebugSettitle(const char*);720 zTitle = Tcl_GetString(objv[1]);721 sqlite3MemdebugSettitle(zTitle);722 }723#endif724 return TCL_OK;725}726 727#define MALLOC_LOG_FRAMES 10 728#define MALLOC_LOG_KEYINTS ( \729 10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \730)731static Tcl_HashTable aMallocLog;732static int mallocLogEnabled = 0;733 734typedef struct MallocLog MallocLog;735struct MallocLog {736 int nCall;737 int nByte;738};739 740#ifdef SQLITE_MEMDEBUG741static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){742 if( mallocLogEnabled ){743 MallocLog *pLog;744 Tcl_HashEntry *pEntry;745 int isNew;746 747 int aKey[MALLOC_LOG_KEYINTS];748 unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;749 750 memset(aKey, 0, nKey);751 if( (sizeof(void*)*nFrame)<nKey ){752 nKey = nFrame*sizeof(void*);753 }754 memcpy(aKey, aFrame, nKey);755 756 pEntry = Tcl_CreateHashEntry(&aMallocLog, (const char *)aKey, &isNew);757 if( isNew ){758 pLog = (MallocLog *)Tcl_Alloc(sizeof(MallocLog));759 memset(pLog, 0, sizeof(MallocLog));760 Tcl_SetHashValue(pEntry, (ClientData)pLog);761 }else{762 pLog = (MallocLog *)Tcl_GetHashValue(pEntry);763 }764 765 pLog->nCall++;766 pLog->nByte += nByte;767 }768}769#endif /* SQLITE_MEMDEBUG */770 771static void test_memdebug_log_clear(void){772 Tcl_HashSearch search;773 Tcl_HashEntry *pEntry;774 for(775 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);776 pEntry;777 pEntry=Tcl_NextHashEntry(&search)778 ){779 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);780 Tcl_Free((char *)pLog);781 }782 Tcl_DeleteHashTable(&aMallocLog);783 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);784}785 786static int SQLITE_TCLAPI test_memdebug_log(787 void * clientData,788 Tcl_Interp *interp,789 int objc,790 Tcl_Obj *CONST objv[]791){792 static int isInit = 0;793 int iSub;794 795 static const char *MB_strs[] = { "start", "stop", "dump", "clear", "sync" };796 enum MB_enum { 797 MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC 798 };799 800 if( !isInit ){801#ifdef SQLITE_MEMDEBUG802 extern void sqlite3MemdebugBacktraceCallback(803 void (*xBacktrace)(int, int, void **));804 sqlite3MemdebugBacktraceCallback(test_memdebug_callback);805#endif806 Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);807 isInit = 1;808 }809 810 if( objc<2 ){811 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");812 }813 if( Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, &iSub) ){814 return TCL_ERROR;815 }816 817 switch( (enum MB_enum)iSub ){818 case MB_LOG_START:819 mallocLogEnabled = 1;820 break;821 case MB_LOG_STOP:822 mallocLogEnabled = 0;823 break;824 case MB_LOG_DUMP: {825 Tcl_HashSearch search;826 Tcl_HashEntry *pEntry;827 Tcl_Obj *pRet = Tcl_NewObj();828 829 assert(sizeof(Tcl_WideInt)>=sizeof(void*));830 831 for(832 pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);833 pEntry;834 pEntry=Tcl_NextHashEntry(&search)835 ){836 Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];837 MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);838 Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);839 int ii;840 841 apElem[0] = Tcl_NewIntObj(pLog->nCall);842 apElem[1] = Tcl_NewIntObj(pLog->nByte);843 for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){844 apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);845 }846 847 Tcl_ListObjAppendElement(interp, pRet,848 Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)849 );850 }851 852 Tcl_SetObjResult(interp, pRet);853 break;854 }855 case MB_LOG_CLEAR: {856 test_memdebug_log_clear();857 break;858 }859 860 case MB_LOG_SYNC: {861#ifdef SQLITE_MEMDEBUG862 extern void sqlite3MemdebugSync();863 test_memdebug_log_clear();864 mallocLogEnabled = 1;865 sqlite3MemdebugSync();866#endif867 break;868 }869 }870 871 return TCL_OK;872}873 874/*875** Usage: sqlite3_config_pagecache SIZE N876**877** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.878** The buffer is static and is of limited size. N might be879** adjusted downward as needed to accommodate the requested size.880** The revised value of N is returned.881**882** A negative SIZE causes the buffer pointer to be NULL.883*/884static int SQLITE_TCLAPI test_config_pagecache(885 void * clientData,886 Tcl_Interp *interp,887 int objc,888 Tcl_Obj *CONST objv[]889){890 int sz, N;891 Tcl_Obj *pRes;892 static char *buf = 0;893 if( objc!=3 ){894 Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");895 return TCL_ERROR;896 }897 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;898 if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;899 free(buf);900 buf = 0;901 902 /* Set the return value */903 pRes = Tcl_NewObj();904 Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.szPage));905 Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(sqlite3GlobalConfig.nPage));906 Tcl_SetObjResult(interp, pRes);907 908 if( sz<0 ){909 sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, 0);910 }else{911 buf = malloc( sz*N );912 sqlite3_config(SQLITE_CONFIG_PAGECACHE, buf, sz, N);913 }914 return TCL_OK;915}916 917/*918** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED919**920** Set up the alternative test page cache. Install if INSTALL_FLAG is921** true and uninstall (reverting to the default page cache) if INSTALL_FLAG922** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive923** which determines the chance of discarding a page when unpinned. 100924** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator925** seed.926*/927static int SQLITE_TCLAPI test_alt_pcache(928 void * clientData,929 Tcl_Interp *interp,930 int objc,931 Tcl_Obj *CONST objv[]932){933 int installFlag;934 int discardChance = 0;935 int prngSeed = 0;936 int highStress = 0;937 extern void installTestPCache(int,unsigned,unsigned,unsigned);938 if( objc<2 || objc>5 ){939 Tcl_WrongNumArgs(interp, 1, objv, 940 "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");941 return TCL_ERROR;942 }943 if( Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL_ERROR;944 if( objc>=3 && Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){945 return TCL_ERROR;946 }947 if( objc>=4 && Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){948 return TCL_ERROR;949 }950 if( objc>=5 && Tcl_GetIntFromObj(interp, objv[4], &highStress) ){951 return TCL_ERROR;952 }953 if( discardChance<0 || discardChance>100 ){954 Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",955 (char*)0);956 return TCL_ERROR;957 }958 installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,959 (unsigned)highStress);960 return TCL_OK;961}962 963/*964** Usage: sqlite3_config_memstatus BOOLEAN965**966** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.967*/968static int SQLITE_TCLAPI test_config_memstatus(969 void * clientData,970 Tcl_Interp *interp,971 int objc,972 Tcl_Obj *CONST objv[]973){974 int enable, rc;975 if( objc!=2 ){976 Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");977 return TCL_ERROR;978 }979 if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR;980 rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable);981 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));982 return TCL_OK;983}984 985/*986** Usage: sqlite3_config_lookaside SIZE COUNT987**988*/989static int SQLITE_TCLAPI test_config_lookaside(990 void * clientData,991 Tcl_Interp *interp,992 int objc,993 Tcl_Obj *CONST objv[]994){995 int sz, cnt;996 Tcl_Obj *pRet;997 if( objc!=3 ){998 Tcl_WrongNumArgs(interp, 1, objv, "SIZE COUNT");999 return TCL_ERROR;1000 }1001 if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;1002 if( Tcl_GetIntFromObj(interp, objv[2], &cnt) ) return TCL_ERROR;1003 pRet = Tcl_NewObj();1004 Tcl_ListObjAppendElement(1005 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.szLookaside)1006 );1007 Tcl_ListObjAppendElement(1008 interp, pRet, Tcl_NewIntObj(sqlite3GlobalConfig.nLookaside)1009 );1010 sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, cnt);1011 Tcl_SetObjResult(interp, pRet);1012 return TCL_OK;1013}1014 1015 1016/*1017** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT1018**1019** There are two static buffers with BUFID 1 and 2. Each static buffer1020** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL1021** which will cause sqlite3_db_config() to allocate space on its own.1022*/1023static int SQLITE_TCLAPI test_db_config_lookaside(1024 void * clientData,1025 Tcl_Interp *interp,1026 int objc,1027 Tcl_Obj *CONST objv[]1028){1029 int rc;1030 int sz, cnt;1031 sqlite3 *db;1032 int bufid;1033 static char azBuf[2][10000];1034 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);1035 if( objc!=5 ){1036 Tcl_WrongNumArgs(interp, 1, objv, "BUFID SIZE COUNT");1037 return TCL_ERROR;1038 }1039 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;1040 if( Tcl_GetIntFromObj(interp, objv[2], &bufid) ) return TCL_ERROR;1041 if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;1042 if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;1043 if( bufid==0 ){1044 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);1045 }else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){1046 rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);1047 }else{1048 Tcl_AppendResult(interp, "illegal arguments - see documentation", (char*)0);1049 return TCL_ERROR;1050 }1051 Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));1052 return TCL_OK;1053}1054 1055/*1056** Usage: sqlite3_config_heap NBYTE NMINALLOC1057*/1058static int SQLITE_TCLAPI test_config_heap(1059 void * clientData, 1060 Tcl_Interp *interp,1061 int objc,1062 Tcl_Obj *CONST objv[]1063){1064 static char *zBuf; /* Use this memory */1065 int nByte; /* Size of buffer to pass to sqlite3_config() */1066 int nMinAlloc; /* Size of minimum allocation */1067 int rc; /* Return code of sqlite3_config() */1068 1069 Tcl_Obj * CONST *aArg = &objv[1];1070 int nArg = objc-1;1071 1072 if( nArg!=2 ){1073 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");1074 return TCL_ERROR;1075 }1076 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;1077 if( Tcl_GetIntFromObj(interp, aArg[1], &nMinAlloc) ) return TCL_ERROR;1078 1079 if( nByte==0 ){1080 free( zBuf );1081 zBuf = 0;1082 rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void*)0, 0, 0);1083 }else{1084 zBuf = realloc(zBuf, nByte);1085 rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);1086 }1087 1088 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);1089 return TCL_OK;1090}1091 1092/*1093** Usage: sqlite3_config_heap_size NBYTE1094*/1095static int SQLITE_TCLAPI test_config_heap_size(1096 void * clientData, 1097 Tcl_Interp *interp,1098 int objc,1099 Tcl_Obj *CONST objv[]1100){1101 int nByte; /* Size to pass to sqlite3_config() */1102 int rc; /* Return code of sqlite3_config() */1103 1104 Tcl_Obj * CONST *aArg = &objv[1];1105 int nArg = objc-1;1106 1107 if( nArg!=1 ){1108 Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");1109 return TCL_ERROR;1110 }1111 if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;1112 1113 rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);1114 1115 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);1116 return TCL_OK;1117}1118 1119/*1120** Usage: sqlite3_config_error [DB]1121**1122** Invoke sqlite3_config() or sqlite3_db_config() with invalid1123** opcodes and verify that they return errors.1124*/1125static int SQLITE_TCLAPI test_config_error(1126 void * clientData, 1127 Tcl_Interp *interp,1128 int objc,1129 Tcl_Obj *CONST objv[]1130){1131 sqlite3 *db;1132 extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);1133 1134 if( objc!=2 && objc!=1 ){1135 Tcl_WrongNumArgs(interp, 1, objv, "[DB]");1136 return TCL_ERROR;1137 }1138 if( objc==2 ){1139 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;1140 if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){1141 Tcl_AppendResult(interp, 1142 "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",1143 (char*)0);1144 return TCL_ERROR;1145 }1146 }else{1147 if( sqlite3_config(99999)!=SQLITE_ERROR ){1148 Tcl_AppendResult(interp, 1149 "sqlite3_config(99999) does not return SQLITE_ERROR",1150 (char*)0);1151 return TCL_ERROR;1152 }1153 }1154 return TCL_OK;1155}1156 1157/*1158** Usage: sqlite3_config_uri BOOLEAN1159**1160** Enables or disables interpretation of URI parameters by default using1161** SQLITE_CONFIG_URI.1162*/1163static int SQLITE_TCLAPI test_config_uri(1164 void * clientData, 1165 Tcl_Interp *interp,1166 int objc,1167 Tcl_Obj *CONST objv[]1168){1169 int rc;1170 int bOpenUri;1171 1172 if( objc!=2 ){1173 Tcl_WrongNumArgs(interp, 1, objv, "BOOL");1174 return TCL_ERROR;1175 }1176 if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){1177 return TCL_ERROR;1178 }1179 1180 rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);1181 Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);1182 1183 return TCL_OK;1184}1185 1186/*1187** Usage: sqlite3_config_cis BOOLEAN1188**1189** Enables or disables the use of the covering-index scan optimization.1190** SQLITE_CONFIG_COVERING_INDEX_SCAN.1191*/1192static int SQLITE_TCLAPI test_config_cis(1193 void * clientData, 1194 Tcl_Interp *interp,1195 int objc,1196 Tcl_Obj *CONST objv[]1197){1198 int rc;1199 int bUseCis;1200 