xref: /sqlite-3.40.0/src/fault.c (revision d09414cd)
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