aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fault.c179
-rw-r--r--src/main.c14
-rw-r--r--src/malloc.c28
-rw-r--r--src/sqlite.h.in3
-rw-r--r--src/sqliteInt.h3
-rw-r--r--src/test_malloc.c30
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++){