/ Check-in [d22cd2a5]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Move the malloc() failure simulation out of malloc.c and into a separate sqlite3_mem_methods interface. Still some related changes to come. (CVS 5250)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d22cd2a59f472f4eaf80aa9f55fbff2514ca428d
User & Date: danielk1977 2008-06-19 18:17:50
Context
2008-06-19
18:39
Unset global TCL variables in the func.test script prior to use to avoid conflicts from other scripts. (CVS 5251) check-in: 9b04e10f user: drh tags: trunk
18:17
Move the malloc() failure simulation out of malloc.c and into a separate sqlite3_mem_methods interface. Still some related changes to come. (CVS 5250) check-in: d22cd2a5 user: danielk1977 tags: trunk
17:54
Documentation and test-script updates. (CVS 5249) check-in: 68d4f795 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/fault.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49




50












































































51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
** compiled with -DSQLITE_OMIT_BUILTIN_TEST=1.  There is a very
** small performance hit for leaving the fault injector in the code.
** Commerical products will probably want to omit the fault injector
** from production builds.  But safety-critical systems who work
** 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 $
*/
#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 {
  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];





/*












































































** This routine configures and enables a fault injector.  After
** calling this routine, aFaultStep() 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;
}

/*
** Return the number of faults (both hard and benign faults) that have
** occurred since the injector was last configured.
*/
int sqlite3FaultFailures(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  return aFault[id].nFail;
}

/*
** Return the number of benign faults that have occurred since the
** injector was last configured.
*/
int sqlite3FaultBenignFailures(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  return aFault[id].nBenign;
}

/*
** Return the number of successes that will occur before the next failure.
** 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;
  }else{
    return -1;
  }
}

/* 
** After this routine causes subsequent faults to be either benign
................................................................................
** recoverable simply by not carrying out the resize.  The hash table
** will continue to function normally.  So a malloc failure during
** a hash table resize is a benign fault.  
*/
void sqlite3FaultBeginBenign(int id){
  if( id<0 ){
    for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){
      aFault[id].benign++;
    }
  }else{
    assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
    aFault[id].benign++;
  }
}
void sqlite3FaultEndBenign(int id){
  if( id<0 ){
    for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){
      assert( aFault[id].benign>0 );
      aFault[id].benign--;
    }
  }else{
    assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
    assert( aFault[id].benign>0 );
    aFault[id].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++;
}


/*
** 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;
  }
  sqlite3Fault();
  aFault[id].nFail++;
  if( aFault[id].benign>0 ){
    aFault[id].nBenign++;
  }
  aFault[id].nRepeat--;
  if( aFault[id].nRepeat<=0 ){
    aFault[id].enable = 0;
  }
  return 1;  
}

#endif /* SQLITE_OMIT_BUILTIN_TEST */







|



<
<






|






<

>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|




<
|
|
|
|
|
|








|







|
<







<
|
|







 







|



|





|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
172
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236





** compiled with -DSQLITE_OMIT_BUILTIN_TEST=1.  There is a very
** small performance hit for leaving the fault injector in the code.
** Commerical products will probably want to omit the fault injector
** from production builds.  But safety-critical systems who work
** 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.7 2008/06/19 18:17:50 danielk1977 Exp $
*/
#include "sqliteInt.h"



/*
** 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 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 */


  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, 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){

  memfault.iCountdown = nDelay;
  memfault.nRepeat = nRepeat;
  memfault.nBenign = 0;
  memfault.nFail = 0;
  memfault.enable = nDelay>=0;
  memfault.benign = 0;
}

/*
** Return the number of faults (both hard and benign faults) that have
** occurred since the injector was last configured.
*/
int sqlite3FaultFailures(int id){
  assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
  return memfault.nFail;
}

/*
** Return the number of benign faults that have occurred since the
** injector was last configured.
*/
int sqlite3FaultBenignFailures(int id){
  return memfault.nBenign;

}

/*
** Return the number of successes that will occur before the next failure.
** If no failures are scheduled, return -1.
*/
int sqlite3FaultPending(int id){

  if( memfault.enable ){
    return memfault.iCountdown;
  }else{
    return -1;
  }
}

/* 
** After this routine causes subsequent faults to be either benign
................................................................................
** recoverable simply by not carrying out the resize.  The hash table
** will continue to function normally.  So a malloc failure during
** a hash table resize is a benign fault.  
*/
void sqlite3FaultBeginBenign(int id){
  if( id<0 ){
    for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){
      memfault.benign++;
    }
  }else{
    assert( id>=0 && id<SQLITE_FAULTINJECTOR_COUNT );
    memfault.benign++;
  }
}
void sqlite3FaultEndBenign(int id){
  if( id<0 ){
    for(id=0; id<SQLITE_FAULTINJECTOR_COUNT; id++){
      assert( memfault.benign>0 );
      memfault.benign--;
    }
  }else{
    assert( memfault.benign>0 );
    memfault.benign--;
  }
}

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);

  if( install==memfault.isInstalled ){
    return SQLITE_ERROR;
  }

  rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memfault.m);
  assert(memfault.m.xMalloc);
  if( rc==SQLITE_OK ){
    rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &m);
  }

  if( rc==SQLITE_OK ){
    memfault.isInstalled = 1;
  }
  return rc;
}






Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
1811
1812
1813
1814
1815
1816
1817












1818
1819
1820
1821
1822
1823
1824
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** 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 $
*/
#include "sqliteInt.h"
#include <ctype.h>

#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
................................................................................
    ** If no failures are scheduled, return -1.
    */
    case SQLITE_TESTCTRL_FAULT_PENDING: {
      int id = va_arg(ap, int);
      rc = sqlite3FaultPending(id);
      break;
    }













    /*
    ** Save the current state of the PRNG.
    */
    case SQLITE_TESTCTRL_PRNG_SAVE: {
      sqlite3PrngSaveState();
      break;







|







 







>
>
>
>
>
>
>
>
>
>
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.453 2008/06/19 18:17:50 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
................................................................................
    ** If no failures are scheduled, return -1.
    */
    case SQLITE_TESTCTRL_FAULT_PENDING: {
      int id = va_arg(ap, int);
      rc = sqlite3FaultPending(id);
      break;
    }

    /*
    ** 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: {
      sqlite3PrngSaveState();
      break;

Changes to src/malloc.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
...
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.21 2008/06/19 00:16:08 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** This routine runs when the memory allocator sees that the
................................................................................
  sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
  if( mem0.alarmCallback!=0 ){
    int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    if( nUsed+nFull >= mem0.alarmThreshold ){
      sqlite3MallocAlarm(nFull);
    }
  }
  if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
    p = 0;
  }else{
    p = sqlite3Config.m.xMalloc(nFull);
    if( p==0 ){
      sqlite3MallocAlarm(nFull);
      p = malloc(nFull);
    }
  }
  if( p ) sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
  *pp = p;
  return nFull;
}

/*
................................................................................
** routine is intended to get memory to old large transient data
** structures that would not normally fit on the stack of an
** embedded processor.
*/
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
  ** is outstanding at one time.  (This is only checked in the
  ** single-threaded case since checking in the multi-threaded case
  ** would be much more complicated.) */
  assert( scratchAllocOut==0 );
................................................................................
** consumed.  Otherwise, failover to sqlite3Malloc().
*/
void *sqlite3PageMalloc(int n){
  void *p;
  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;
  }else{  
    sqlite3_mutex_enter(mem0.mutex);
    if( mem0.nPageFree==0 ){
      sqlite3_mutex_leave(mem0.mutex);
................................................................................
    if( nOld==nNew ){
      pNew = pOld;
    }else{
      if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= 
            mem0.alarmThreshold ){
        sqlite3MallocAlarm(nNew-nOld);
      }
      if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){
        pNew = 0;
      }else{
        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);
      }
    }
    sqlite3_mutex_leave(mem0.mutex);
  }else{







|







 







<
<
<
|
|
|
|
<







 







<
<
<







 







<
<
<







 







<
<
<
|
|
|
|
<







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
209
210
211
212
213
214
215



216
217
218
219

220
221
222
223
224
225
226
...
271
272
273
274
275
276
277



278
279
280
281
282
283
284
...
366
367
368
369
370
371
372



373
374
375
376
377
378
379
...
473
474
475
476
477
478
479



480
481
482
483

484
485
486
487
488
489
490
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.22 2008/06/19 18:17:50 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** This routine runs when the memory allocator sees that the
................................................................................
  sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
  if( mem0.alarmCallback!=0 ){
    int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
    if( nUsed+nFull >= mem0.alarmThreshold ){
      sqlite3MallocAlarm(nFull);
    }
  }



  p = sqlite3Config.m.xMalloc(nFull);
  if( p==0 && mem0.alarmCallback ){
    sqlite3MallocAlarm(nFull);
    p = sqlite3Config.m.xMalloc(nFull);

  }
  if( p ) sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
  *pp = p;
  return nFull;
}

/*
................................................................................
** routine is intended to get memory to old large transient data
** structures that would not normally fit on the stack of an
** embedded processor.
*/
void *sqlite3ScratchMalloc(int n){
  void *p;
  assert( n>0 );




#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
  /* Verify that no more than one scratch allocation per thread
  ** is outstanding at one time.  (This is only checked in the
  ** single-threaded case since checking in the multi-threaded case
  ** would be much more complicated.) */
  assert( scratchAllocOut==0 );
................................................................................
** consumed.  Otherwise, failover to sqlite3Malloc().
*/
void *sqlite3PageMalloc(int n){
  void *p;
  assert( n>0 );
  assert( (n & (n-1))==0 );
  assert( n>=512 && n<=32768 );




  if( sqlite3Config.szPage<n ){
    goto page_overflow;
  }else{  
    sqlite3_mutex_enter(mem0.mutex);
    if( mem0.nPageFree==0 ){
      sqlite3_mutex_leave(mem0.mutex);
................................................................................
    if( nOld==nNew ){
      pNew = pOld;
    }else{
      if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= 
            mem0.alarmThreshold ){
        sqlite3MallocAlarm(nNew-nOld);
      }



      pNew = sqlite3Config.m.xRealloc(pOld, nNew);
      if( pNew==0 && mem0.alarmCallback ){
        sqlite3MallocAlarm(nBytes);
        pNew = sqlite3Config.m.xRealloc(pOld, nNew);

      }
      if( pNew ){
        sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
      }
    }
    sqlite3_mutex_leave(mem0.mutex);
  }else{

Changes to src/sqlite.h.in.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
6056
6057
6058
6059
6060
6061
6062

6063
6064
6065
6066
6067
6068
6069
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** 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 $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
#define SQLITE_TESTCTRL_FAULT_FAILURES           2
#define SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES    3
#define SQLITE_TESTCTRL_FAULT_PENDING            4
#define SQLITE_TESTCTRL_PRNG_SAVE                5
#define SQLITE_TESTCTRL_PRNG_RESTORE             6
#define SQLITE_TESTCTRL_PRNG_RESET               7
#define SQLITE_TESTCTRL_BITVEC_TEST              8


/*
** CAPI3REF: SQLite Runtime Status {F17200}
**
** This interface is used to retrieve run-time status information
** about the preformance of SQLite, and optionally to reset various
** highwater marks.  The first argument is an integer code for







|







 







>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.341 2008/06/19 18:17:50 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
#define SQLITE_TESTCTRL_FAULT_FAILURES           2
#define SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES    3
#define SQLITE_TESTCTRL_FAULT_PENDING            4
#define SQLITE_TESTCTRL_PRNG_SAVE                5
#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}
**
** This interface is used to retrieve run-time status information
** about the preformance of SQLite, and optionally to reset various
** highwater marks.  The first argument is an integer code for

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2211
2212
2213
2214
2215
2216
2217

2218
2219
2220
2221
2222
2223
2224
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.717 2008/06/19 01:03:18 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
  void sqlite3FaultConfig(int,int,int);
  int sqlite3FaultFailures(int);
  int sqlite3FaultBenignFailures(int);
  int sqlite3FaultPending(int);
  void sqlite3FaultBeginBenign(int);
  void sqlite3FaultEndBenign(int);
  int sqlite3FaultStep(int);

#else
# define sqlite3FaultConfig(A,B,C)
# define sqlite3FaultFailures(A)         0
# define sqlite3FaultBenignFailures(A)   0
# define sqlite3FaultPending(A)          (-1)
# define sqlite3FaultBeginBenign(A)
# define sqlite3FaultEndBenign(A)







|







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.718 2008/06/19 18:17:50 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
  void sqlite3FaultConfig(int,int,int);
  int sqlite3FaultFailures(int);
  int sqlite3FaultBenignFailures(int);
  int sqlite3FaultPending(int);
  void sqlite3FaultBeginBenign(int);
  void sqlite3FaultEndBenign(int);
  int sqlite3FaultStep(int);
  int sqlite3FaultsimInstall(int);
#else
# define sqlite3FaultConfig(A,B,C)
# define sqlite3FaultFailures(A)         0
# define sqlite3FaultBenignFailures(A)   0
# define sqlite3FaultPending(A)          (-1)
# define sqlite3FaultBeginBenign(A)
# define sqlite3FaultEndBenign(A)

Changes to src/test_malloc.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22


23
24
25
26
27
28
29
...
775
776
777
778
779
780
781
























782
783
784
785
786
787
788
...
801
802
803
804
805
806
807


808
809
810
811
812
813
814
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** 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 $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>



/*
** Transform pointers to text and back again
*/
static void pointerToText(void *p, char *z){
  static const char zHex[] = "0123456789abcdef";
  int i, k;
................................................................................
  pResult = Tcl_NewObj();
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
  Tcl_SetObjResult(interp, pResult);
  return TCL_OK;
}

























/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_malloc_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
................................................................................
     { "sqlite3_memdebug_pending",   test_memdebug_pending         },
     { "sqlite3_memdebug_settitle",  test_memdebug_settitle        },
     { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
     { "sqlite3_memdebug_log",       test_memdebug_log             },
     { "sqlite3_config_scratch",     test_config_scratch           },
     { "sqlite3_config_pagecache",   test_config_pagecache         },
     { "sqlite3_status",             test_status                   },


  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
  }
  return TCL_OK;
}







|






>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code used to implement test interfaces to the
** memory allocation subsystem.
**
** $Id: test_malloc.c,v 1.26 2008/06/19 18:17:50 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

const char *sqlite3TestErrorName(int);

/*
** Transform pointers to text and back again
*/
static void pointerToText(void *p, char *z){
  static const char zHex[] = "0123456789abcdef";
  int i, k;
................................................................................
  pResult = Tcl_NewObj();
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(iValue));
  Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(mxValue));
  Tcl_SetObjResult(interp, pResult);
  return TCL_OK;
}

/*
** 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){
  static struct {
     char *zName;
................................................................................
     { "sqlite3_memdebug_pending",   test_memdebug_pending         },
     { "sqlite3_memdebug_settitle",  test_memdebug_settitle        },
     { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count },
     { "sqlite3_memdebug_log",       test_memdebug_log             },
     { "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++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
  }
  return TCL_OK;
}

Changes to test/malloc.test.

12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
# This file attempts to check the behavior of the SQLite library in 
# an out-of-memory situation. When compiled with -DSQLITE_DEBUG=1, 
# the SQLite library accepts a special command (sqlite3_memdebug_fail N C)
# which causes the N-th malloc to fail.  This special feature is used
# to see what happens in the library if a malloc were to really fail
# due to an out-of-memory situation.
#
# $Id: malloc.test,v 1.61 2008/04/17 14:16:42 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Only run these tests if memory debugging is turned on.
#
source $testdir/malloc_common.tcl
if {!$MEMDEBUG} {
   puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test







|



>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# This file attempts to check the behavior of the SQLite library in 
# an out-of-memory situation. When compiled with -DSQLITE_DEBUG=1, 
# the SQLite library accepts a special command (sqlite3_memdebug_fail N C)
# which causes the N-th malloc to fail.  This special feature is used
# to see what happens in the library if a malloc were to really fail
# due to an out-of-memory situation.
#
# $Id: malloc.test,v 1.62 2008/06/19 18:17:50 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Only run these tests if memory debugging is turned on.
#
source $testdir/malloc_common.tcl
if {!$MEMDEBUG} {
   puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test

Changes to test/malloc2.test.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# This file attempts to check that the library can recover from a malloc()
# failure when sqlite3_global_recover() is invoked.
#
# (Later:) The sqlite3_global_recover() interface is now a no-op.
# Recovery from malloc() failures is automatic.  But we keep these
# tests around because you can never have too many test cases.
#
# $Id: malloc2.test,v 1.12 2008/02/18 22:24:58 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl

# Only run these tests if memory debugging is turned on.
#
................................................................................
sqlite3_extended_result_codes db 1

proc do_malloc2_test {tn args} {
  array set ::mallocopts $args
  set sum [allcksum db]
  save_prng_state

  for {set ::n 784} {true} {incr ::n} {

    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    restore_prng_state
    sqlite3_memdebug_fail $::n -repeat 1
    do_test malloc2-$tn.$::n.2 {
      set res [catchsql [string trim $::mallocopts(-sql)]]







|







 







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# This file attempts to check that the library can recover from a malloc()
# failure when sqlite3_global_recover() is invoked.
#
# (Later:) The sqlite3_global_recover() interface is now a no-op.
# Recovery from malloc() failures is automatic.  But we keep these
# tests around because you can never have too many test cases.
#
# $Id: malloc2.test,v 1.13 2008/06/19 18:17:50 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl

# Only run these tests if memory debugging is turned on.
#
................................................................................
sqlite3_extended_result_codes db 1

proc do_malloc2_test {tn args} {
  array set ::mallocopts $args
  set sum [allcksum db]
  save_prng_state

  for {set ::n 1} {true} {incr ::n} {

    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    restore_prng_state
    sqlite3_memdebug_fail $::n -repeat 1
    do_test malloc2-$tn.$::n.2 {
      set res [catchsql [string trim $::mallocopts(-sql)]]

Changes to test/malloc_common.tcl.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25





26
27
28
29
30
31
32
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains common code used by many different malloc tests
# within the test suite.
#
# $Id: malloc_common.tcl,v 1.16 2008/03/21 16:45:48 drh Exp $

# If we did not compile with malloc testing enabled, then do nothing.
#
ifcapable builtin_test {
  set MEMDEBUG 1
} else {
  set MEMDEBUG 0
  return 0
}






# Usage: do_malloc_test <test number> <options...>
#
# The first argument, <test number>, is an integer used to name the
# tests executed by this proc. Options are as follows:
#
#     -tclprep          TCL script to run to prepare test.
#     -sqlprep          SQL script to run to prepare test.







|










>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains common code used by many different malloc tests
# within the test suite.
#
# $Id: malloc_common.tcl,v 1.17 2008/06/19 18:17:50 danielk1977 Exp $

# If we did not compile with malloc testing enabled, then do nothing.
#
ifcapable builtin_test {
  set MEMDEBUG 1
} else {
  set MEMDEBUG 0
  return 0
}

catch {db close}
sqlite3_shutdown
catch {install_malloc_faultsim 1} msg
sqlite3 db test.db

# Usage: do_malloc_test <test number> <options...>
#
# The first argument, <test number>, is an integer used to name the
# tests executed by this proc. Options are as follows:
#
#     -tclprep          TCL script to run to prepare test.
#     -sqlprep          SQL script to run to prepare test.