diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/fault.c | 179 | ||||
-rw-r--r-- | src/main.c | 14 | ||||
-rw-r--r-- | src/malloc.c | 28 | ||||
-rw-r--r-- | src/sqlite.h.in | 3 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/test_malloc.c | 30 |
6 files changed, 177 insertions, 80 deletions
diff --git a/src/fault.c b/src/fault.c index f96a3fe85..c2f9dada8 100644 --- a/src/fault.c +++ b/src/fault.c @@ -26,41 +26,117 @@ ** under the motto "fly what you test and test what you fly" may ** choose to leave the fault injector enabled even in production. ** -** $Id: fault.c,v 1.6 2008/05/15 19:43:53 drh Exp $ +** $Id: fault.c,v 1.7 2008/06/19 18:17:50 danielk1977 Exp $ */ #include "sqliteInt.h" -#ifndef SQLITE_OMIT_BUILTIN_TEST - /* ** There can be various kinds of faults. For example, there can be ** a memory allocation failure. Or an I/O failure. For each different ** fault type, there is a separate FaultInjector structure to keep track ** of the status of that fault. */ -static struct FaultInjector { +static struct MemFault { int iCountdown; /* Number of pending successes before we hit 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 */ u8 enable; /* True if enabled */ i16 benign; /* Positive if next failure will be benign */ -} aFault[SQLITE_FAULTINJECTOR_COUNT]; + + int isInstalled; + 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 int cnt = 0; + cnt++; +} + +/* +** 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(){ + if( likely(!memfault.enable) ){ + return 0; + } + if( memfault.iCountdown>0 ){ + memfault.iCountdown--; + return 0; + } + sqlite3Fault(); + memfault.nFail++; + if( memfault.benign>0 ){ + memfault.nBenign++; + } + memfault.nRepeat--; + if( memfault.nRepeat<=0 ){ + memfault.enable = 0; + } + return 1; +} + +static void *faultsimMalloc(int n){ + void *p = 0; + if( !faultsimStep() ){ + p = memfault.m.xMalloc(n); + } + return p; +} + + +static void *faultsimRealloc(void *pOld, int n){ + void *p = 0; + if( !faultsimStep() ){ + p = memfault.m.xRealloc(pOld, n); + } + return p; +} + +/* +** The following method calls are passed directly through to the underlying +** malloc system: +** +** xFree +** xSize +** xRoundup +** xInit +** xShutdown +*/ +static void faultsimFree(void *p){ + memfault.m.xFree(p); +} +static int faultsimSize(void *p){ + return memfault.m.xSize(p); +} +static int faultsimRoundup(int n){ + return memfault.m.xRoundup(n); +} +static int faultsimInit(void *p){ + return memfault.m.xInit(memfault.m.pAppData); +} +static void faultsimShutdown(void *p){ + memfault.m.xShutdown(memfault.m.pAppData); +} /* ** This routine configures and enables a fault injector. After -** calling this routine, aFaultStep() will return false (zero) +** calling this routine, a FaultStep() will return false (zero) ** nDelay times, then it will return true nRepeat times, ** then it will again begin returning false. */ void sqlite3FaultConfig(int id, int nDelay, int nRepeat){ - assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - aFault[id].iCountdown = nDelay; - aFault[id].nRepeat = nRepeat; - aFault[id].nBenign = 0; - aFault[id].nFail = 0; - aFault[id].enable = nDelay>=0; - aFault[id].benign = 0; + memfault.iCountdown = nDelay; + memfault.nRepeat = nRepeat; + memfault.nBenign = 0; + memfault.nFail = 0; + memfault.enable = nDelay>=0; + memfault.benign = 0; } /* @@ -69,7 +145,7 @@ void sqlite3FaultConfig(int id, int nDelay, int nRepeat){ */ int sqlite3FaultFailures(int id){ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - return aFault[id].nFail; + return memfault.nFail; } /* @@ -77,8 +153,7 @@ int sqlite3FaultFailures(int id){ ** injector was last configured. */ int sqlite3FaultBenignFailures(int id){ - assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - return aFault[id].nBenign; + return memfault.nBenign; } /* @@ -86,9 +161,8 @@ int sqlite3FaultBenignFailures(int id){ ** If no failures are scheduled, return -1. */ int sqlite3FaultPending(int id){ - assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - if( aFault[id].enable ){ - return aFault[id].iCountdown; + if( memfault.enable ){ + return memfault.iCountdown; }else{ return -1; } @@ -109,59 +183,54 @@ int sqlite3FaultPending(int id){ void sqlite3FaultBeginBenign(int id){ if( id<0 ){ for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){ - aFault[id].benign++; + memfault.benign++; } }else{ assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - aFault[id].benign++; + memfault.benign++; } } void sqlite3FaultEndBenign(int id){ if( id<0 ){ for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){ - assert( aFault[id].benign>0 ); - aFault[id].benign--; + assert( memfault.benign>0 ); + memfault.benign--; } }else{ - assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - assert( aFault[id].benign>0 ); - aFault[id].benign--; + assert( memfault.benign>0 ); + memfault.benign--; } } -/* -** This routine exists as a place to set a breakpoint that will -** fire on any simulated fault. -*/ -static void sqlite3Fault(void){ - static int cnt = 0; - cnt++; -} +int sqlite3FaultsimInstall(int install){ + static struct sqlite3_mem_methods m = { + faultsimMalloc, /* xMalloc */ + faultsimFree, /* xFree */ + faultsimRealloc, /* xRealloc */ + faultsimSize, /* xSize */ + faultsimRoundup, /* xRoundup */ + faultsimInit, /* xInit */ + faultsimShutdown, /* xShutdown */ + 0 /* pAppData */ + }; + int rc; + assert(install==1 || install==0); + assert(memfault.isInstalled==1 || memfault.isInstalled==0); -/* -** Check to see if a fault should be simulated. Return true to simulate -** the fault. Return false if the fault should not be simulated. -*/ -int sqlite3FaultStep(int id){ - assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); - if( likely(!aFault[id].enable) ){ - return 0; - } - if( aFault[id].iCountdown>0 ){ - aFault[id].iCountdown--; - return 0; + if( install==memfault.isInstalled ){ + return SQLITE_ERROR; } - sqlite3Fault(); - aFault[id].nFail++; - if( aFault[id].benign>0 ){ - aFault[id].nBenign++; + + rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m); + assert(memfault.m.xMalloc); + if( rc==SQLITE_OK ){ + rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); } - aFault[id].nRepeat--; - if( aFault[id].nRepeat<=0 ){ - aFault[id].enable = 0; + + if( rc==SQLITE_OK ){ + memfault.isInstalled = 1; } - return 1; + return rc; } -#endif /* SQLITE_OMIT_BUILTIN_TEST */ diff --git a/src/main.c b/src/main.c index 870b9f30f..825d1ed01 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.452 2008/06/19 01:03:18 drh Exp $ +** $Id: main.c,v 1.453 2008/06/19 18:17:50 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1817,6 +1817,18 @@ int sqlite3_test_control(int op, ...){ } /* + ** sqlite3_test_control(FAULT_INSTALL, isInstall) + ** + ** If the argument is non-zero, install the fault-simulation malloc layer + ** as a wrapper around the currently installed implementation. + */ + case SQLITE_TESTCTRL_FAULT_INSTALL: { + int isInstall = va_arg(ap, int); + rc = sqlite3FaultsimInstall(isInstall); + break; + } + + /* ** Save the current state of the PRNG. */ case SQLITE_TESTCTRL_PRNG_SAVE: { diff --git a/src/malloc.c b/src/malloc.c index 3441123c6..c107c36ab 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -12,7 +12,7 @@ ** ** Memory allocation functions used throughout sqlite. ** -** $Id: malloc.c,v 1.21 2008/06/19 00:16:08 drh Exp $ +** $Id: malloc.c,v 1.22 2008/06/19 18:17:50 danielk1977 Exp $ */ #include "sqliteInt.h" #include <stdarg.h> @@ -213,14 +213,10 @@ static int mallocWithAlarm(int n, void **pp){ sqlite3MallocAlarm(nFull); } } - if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ - p = 0; - }else{ + p = sqlite3Config.m.xMalloc(nFull); + if( p==0 && mem0.alarmCallback ){ + sqlite3MallocAlarm(nFull); p = sqlite3Config.m.xMalloc(nFull); - if( p==0 ){ - sqlite3MallocAlarm(nFull); - p = malloc(nFull); - } } if( p ) sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull); *pp = p; @@ -279,9 +275,6 @@ static int scratchAllocOut = 0; void *sqlite3ScratchMalloc(int n){ void *p; assert( n>0 ); - if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ - return 0; - } #if SQLITE_THREADSAFE==0 && !defined(NDEBUG) /* Verify that no more than one scratch allocation per thread @@ -377,9 +370,6 @@ void *sqlite3PageMalloc(int n){ assert( n>0 ); assert( (n & (n-1))==0 ); assert( n>=512 && n<=32768 ); - if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ - return 0; - } if( sqlite3Config.szPage<n ){ goto page_overflow; @@ -487,14 +477,10 @@ void *sqlite3Realloc(void *pOld, int nBytes){ mem0.alarmThreshold ){ sqlite3MallocAlarm(nNew-nOld); } - if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ - pNew = 0; - }else{ + pNew = sqlite3Config.m.xRealloc(pOld, nNew); + if( pNew==0 && mem0.alarmCallback ){ + sqlite3MallocAlarm(nBytes); pNew = sqlite3Config.m.xRealloc(pOld, nNew); - if( pNew==0 ){ - sqlite3MallocAlarm(nBytes); - pNew = sqlite3Config.m.xRealloc(pOld, nNew); - } } if( pNew ){ sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 434f4e0bc..d1bf5e1ca 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -30,7 +30,7 @@ ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** -** @(#) $Id: sqlite.h.in,v 1.340 2008/06/19 17:54:33 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.341 2008/06/19 18:17:50 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -6060,6 +6060,7 @@ int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 #define SQLITE_TESTCTRL_BITVEC_TEST 8 +#define SQLITE_TESTCTRL_FAULT_INSTALL 9 /* ** CAPI3REF: SQLite Runtime Status {F17200} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d5e2c74bf..c5e4471c6 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.717 2008/06/19 01:03:18 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.718 2008/06/19 18:17:50 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -2215,6 +2215,7 @@ CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); void sqlite3FaultBeginBenign(int); void sqlite3FaultEndBenign(int); int sqlite3FaultStep(int); + int sqlite3FaultsimInstall(int); #else # define sqlite3FaultConfig(A,B,C) # define sqlite3FaultFailures(A) 0 diff --git a/src/test_malloc.c b/src/test_malloc.c index 4643f2e55..59a2954f7 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.25 2008/06/19 00:16:08 drh Exp $ +** $Id: test_malloc.c,v 1.26 2008/06/19 18:17:50 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -21,6 +21,8 @@ #include <string.h> #include <assert.h> +const char *sqlite3TestErrorName(int); + /* ** Transform pointers to text and back again */ @@ -781,6 +783,30 @@ static int test_status( } /* +** install_malloc_faultsim BOOLEAN +*/ +static int 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 = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, isInstall); + Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); + return TCL_OK; +} + +/* ** Register commands with the TCL interpreter. */ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ @@ -805,6 +831,8 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ { "sqlite3_config_scratch", test_config_scratch }, { "sqlite3_config_pagecache", test_config_pagecache }, { "sqlite3_status", test_status }, + + { "install_malloc_faultsim", test_install_malloc_faultsim }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |