1 /* 2 ** 2008 Jan 22 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** 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 ** This file contains code to implement a fault-injector used for 13 ** testing and verification of SQLite. 14 ** 15 ** Subsystems within SQLite can call sqlite3FaultStep() to see if 16 ** they should simulate a fault. sqlite3FaultStep() normally returns 17 ** zero but will return non-zero if a fault should be simulated. 18 ** Fault injectors can be used, for example, to simulate memory 19 ** allocation failures or I/O errors. 20 ** 21 ** The fault injector is omitted from the code if SQLite is 22 ** compiled with -DSQLITE_OMIT_BUILTIN_TEST=1. There is a very 23 ** small performance hit for leaving the fault injector in the code. 24 ** Commerical products will probably want to omit the fault injector 25 ** from production builds. But safety-critical systems who work 26 ** under the motto "fly what you test and test what you fly" may 27 ** choose to leave the fault injector enabled even in production. 28 ** 29 ** $Id: fault.c,v 1.7 2008/06/19 18:17:50 danielk1977 Exp $ 30 */ 31 #include "sqliteInt.h" 32 33 /* 34 ** There can be various kinds of faults. For example, there can be 35 ** a memory allocation failure. Or an I/O failure. For each different 36 ** fault type, there is a separate FaultInjector structure to keep track 37 ** of the status of that fault. 38 */ 39 static struct MemFault { 40 int iCountdown; /* Number of pending successes before we hit a failure */ 41 int nRepeat; /* Number of times to repeat the failure */ 42 int nBenign; /* Number of benign failures seen since last config */ 43 int nFail; /* Number of failures seen since last config */ 44 u8 enable; /* True if enabled */ 45 i16 benign; /* Positive if next failure will be benign */ 46 47 int isInstalled; 48 sqlite3_mem_methods m; /* 'Real' malloc implementation */ 49 } memfault; 50 51 /* 52 ** This routine exists as a place to set a breakpoint that will 53 ** fire on any simulated malloc() failure. 54 */ 55 static void sqlite3Fault(void){ 56 static int cnt = 0; 57 cnt++; 58 } 59 60 /* 61 ** Check to see if a fault should be simulated. Return true to simulate 62 ** the fault. Return false if the fault should not be simulated. 63 */ 64 static int faultsimStep(){ 65 if( likely(!memfault.enable) ){ 66 return 0; 67 } 68 if( memfault.iCountdown>0 ){ 69 memfault.iCountdown--; 70 return 0; 71 } 72 sqlite3Fault(); 73 memfault.nFail++; 74 if( memfault.benign>0 ){ 75 memfault.nBenign++; 76 } 77 memfault.nRepeat--; 78 if( memfault.nRepeat<=0 ){ 79 memfault.enable = 0; 80 } 81 return 1; 82 } 83 84 static void *faultsimMalloc(int n){ 85 void *p = 0; 86 if( !faultsimStep() ){ 87 p = memfault.m.xMalloc(n); 88 } 89 return p; 90 } 91 92 93 static void *faultsimRealloc(void *pOld, int n){ 94 void *p = 0; 95 if( !faultsimStep() ){ 96 p = memfault.m.xRealloc(pOld, n); 97 } 98 return p; 99 } 100 101 /* 102 ** The following method calls are passed directly through to the underlying 103 ** malloc system: 104 ** 105 ** xFree 106 ** xSize 107 ** xRoundup 108 ** xInit 109 ** xShutdown 110 */ 111 static void faultsimFree(void *p){ 112 memfault.m.xFree(p); 113 } 114 static int faultsimSize(void *p){ 115 return memfault.m.xSize(p); 116 } 117 static int faultsimRoundup(int n){ 118 return memfault.m.xRoundup(n); 119 } 120 static int faultsimInit(void *p){ 121 return memfault.m.xInit(memfault.m.pAppData); 122 } 123 static void faultsimShutdown(void *p){ 124 memfault.m.xShutdown(memfault.m.pAppData); 125 } 126 127 /* 128 ** This routine configures and enables a fault injector. After 129 ** calling this routine, a FaultStep() will return false (zero) 130 ** nDelay times, then it will return true nRepeat times, 131 ** then it will again begin returning false. 132 */ 133 void sqlite3FaultConfig(int id, int nDelay, int nRepeat){ 134 memfault.iCountdown = nDelay; 135 memfault.nRepeat = nRepeat; 136 memfault.nBenign = 0; 137 memfault.nFail = 0; 138 memfault.enable = nDelay>=0; 139 memfault.benign = 0; 140 } 141 142 /* 143 ** Return the number of faults (both hard and benign faults) that have 144 ** occurred since the injector was last configured. 145 */ 146 int sqlite3FaultFailures(int id){ 147 assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); 148 return memfault.nFail; 149 } 150 151 /* 152 ** Return the number of benign faults that have occurred since the 153 ** injector was last configured. 154 */ 155 int sqlite3FaultBenignFailures(int id){ 156 return memfault.nBenign; 157 } 158 159 /* 160 ** Return the number of successes that will occur before the next failure. 161 ** If no failures are scheduled, return -1. 162 */ 163 int sqlite3FaultPending(int id){ 164 if( memfault.enable ){ 165 return memfault.iCountdown; 166 }else{ 167 return -1; 168 } 169 } 170 171 /* 172 ** After this routine causes subsequent faults to be either benign 173 ** or hard (not benign), according to the "enable" parameter. 174 ** 175 ** Most faults are hard. In other words, most faults cause 176 ** an error to be propagated back up to the application interface. 177 ** However, sometimes a fault is easily recoverable. For example, 178 ** if a malloc fails while resizing a hash table, this is completely 179 ** recoverable simply by not carrying out the resize. The hash table 180 ** will continue to function normally. So a malloc failure during 181 ** a hash table resize is a benign fault. 182 */ 183 void sqlite3FaultBeginBenign(int id){ 184 if( id<0 ){ 185 for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){ 186 memfault.benign++; 187 } 188 }else{ 189 assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT ); 190 memfault.benign++; 191 } 192 } 193 void sqlite3FaultEndBenign(int id){ 194 if( id<0 ){ 195 for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){ 196 assert( memfault.benign>0 ); 197 memfault.benign--; 198 } 199 }else{ 200 assert( memfault.benign>0 ); 201 memfault.benign--; 202 } 203 } 204 205 int sqlite3FaultsimInstall(int install){ 206 static struct sqlite3_mem_methods m = { 207 faultsimMalloc, /* xMalloc */ 208 faultsimFree, /* xFree */ 209 faultsimRealloc, /* xRealloc */ 210 faultsimSize, /* xSize */ 211 faultsimRoundup, /* xRoundup */ 212 faultsimInit, /* xInit */ 213 faultsimShutdown, /* xShutdown */ 214 0 /* pAppData */ 215 }; 216 int rc; 217 218 assert(install==1 || install==0); 219 assert(memfault.isInstalled==1 || memfault.isInstalled==0); 220 221 if( install==memfault.isInstalled ){ 222 return SQLITE_ERROR; 223 } 224 225 rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m); 226 assert(memfault.m.xMalloc); 227 if( rc==SQLITE_OK ){ 228 rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m); 229 } 230 231 if( rc==SQLITE_OK ){ 232 memfault.isInstalled = 1; 233 } 234 return rc; 235 } 236 237