Move (almost all) malloc failure test logic from fault.c to test_malloc.c. (CVS 5253)

FossilOrigin-Name: 4ae21e3419ad7e69dd735ca45fdc5a2de93d1840
This commit is contained in:
danielk1977 2008-06-20 11:05:37 +00:00
parent af83758645
commit ef05f2dfe3
6 changed files with 233 additions and 239 deletions

View File

@ -1,5 +1,5 @@
C Patch\sto\smemsubsys1.test\sin\sorder\sto\savoid\sa\ssegfault\sin\stableapi.test.\s(CVS\s5252)
D 2008-06-20T00:03:22
C Move\s(almost\sall)\smalloc\sfailure\stest\slogic\sfrom\sfault.c\sto\stest_malloc.c.\s(CVS\s5253)
D 2008-06-20T11:05:38
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in ff6f90048555a0088f6a4b7406bed5e55a7c4eff
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -105,7 +105,7 @@ F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
F src/date.c e841168e5520bbbb2a1cbcdce7531d8b23017b4d
F src/delete.c d3fc5987f2eb88f7b9549d58a5dfea079a83fe8b
F src/expr.c ecb3b23d3543427cba3e2ac12a6c6ae4bb20d39b
F src/fault.c 34d0f93490a659561a5a41bccb40cc1ef918d265
F src/fault.c dd9ec1b83759b105014bfc831f4b59894af306e9
F src/func.c 1e7d9569570134ac0771a00382d9d4b41c4aa052
F src/global.c 2304cfa3288763bd2fed10caf8c6fbaa2b383f4e
F src/hash.c 283864c1adf546d4f0a6ee3694b62beeda8fbd35
@ -115,7 +115,7 @@ F src/insert.c c2ead6c36566de8e3f130e7ab1431723a269d5d7
F src/journal.c cffd2cd214e58c0e99c3ff632b3bee6c7cbb260e
F src/legacy.c 3626c71fb70912abec9a4312beba753a9ce800df
F src/loadext.c 40024a0f476c1279494876b9a002001b29e5d3e3
F src/main.c ae01b4e90c6a323b689dea1e0af4bf98dc484c7f
F src/main.c 194909a1f45283961f6f6143338600bb8727d3f1
F src/malloc.c 66c0b17a6611547f630b6ea67e14e575b9431507
F src/md5.c 008216bbb5d34c6fbab5357aa68575ad8a31516a
F src/mem1.c 159f10e280f2d9aea597cf938851e61652dd5c3d
@ -145,7 +145,7 @@ F src/select.c 669687459e7d0193c89de06c5dbed55b4a41191c
F src/shell.c a12ea645271b7876c8f080146f48e20b00d367ec
F src/sqlite.h.in bf94fcce7c2da5e92d0037595238efbb4f5d0985
F src/sqlite3ext.h f162a72daef5ebf8b211fe8c0ec96e85d22fbf9b
F src/sqliteInt.h 4d4c0432b5f4918beff36a075015b32244c420c3
F src/sqliteInt.h 1d2417d1ac2280cb1557413bd6f0200cc87b7d28
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 6cb10377992505bd69f1ca1d75c1240a65f25a58
F src/table.c 1fa8f8113ac9cbc09ae4801c6d2a7f0af82c5822
@ -167,7 +167,7 @@ F src/test_devsym.c 6012cb8e3acf812513511025a4fa5d626e0ba19b
F src/test_func.c f4aafa10f17d52c43a64b47717265802e6e552b3
F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
F src/test_loadext.c df8ab3a6481ddebbdf0d28ebac5d9e0790f7860f
F src/test_malloc.c 8c8c0b5cad66b1cb5b8ccca6efec1739572a5978
F src/test_malloc.c cc4111e1f87f99e40a23809cbb2af7d53207b5c1
F src/test_md5.c 28209a4e2068711b5443c33104fe41f21d160071
F src/test_mutex.c 8cfe5c56d5583e07c25c50f59c42ca0104dd24bb
F src/test_onefile.c 1f87d4a21cbfb24a7c35e4333fa0bd34d641f68d
@ -600,7 +600,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 9b04e10f6c00c36652444206d1d8868a560eb56e
R 1d236634be0294388a5fbf26bd78c134
U drh
Z 98968f4980c50e00172f902ce8864e91
P 62411a6e605ec50d8d61233d753cd2ad65c2218d
R 1627595575a0bf69b485a06e6fd086c3
U danielk1977
Z 99658609f6d63a203a5b4c43c3642af7

View File

@ -1 +1 @@
62411a6e605ec50d8d61233d753cd2ad65c2218d
4ae21e3419ad7e69dd735ca45fdc5a2de93d1840

View File

@ -9,168 +9,35 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement a fault-injector used for
** testing and verification of SQLite.
**
** Subsystems within SQLite can call sqlite3FaultStep() to see if
** they should simulate a fault. sqlite3FaultStep() normally returns
** zero but will return non-zero if a fault should be simulated.
** Fault injectors can be used, for example, to simulate memory
** allocation failures or I/O errors.
** This file contains code to support the concept of "benign"
** malloc failures.
**
** The fault injector is omitted from the code if SQLite is
** 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 $
** $Id: fault.c,v 1.8 2008/06/20 11:05:38 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;
#ifndef SQLITE_OMIT_BUILTIN_TEST
/*
** This routine exists as a place to set a breakpoint that will
** fire on any simulated malloc() failure.
** If zero, malloc() failures are non-benign. If non-zero, benign.
*/
static void sqlite3Fault(void){
static int cnt = 0;
cnt++;
}
static int memfault_is_benign = 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.
** Return true if a malloc failures are currently considered to be
** benign. A benign fault does not affect the operation of sqlite.
** By constrast a non-benign fault causes sqlite to fail the current
** operation and return SQLITE_NOMEM to the user.
*/
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;
int sqlite3FaultIsBenign(void){
return memfault_is_benign;
}
/*
** 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
** or hard (not benign), according to the "enable" parameter.
** After this routine causes subsequent malloc faults to be either
** benign or hard (not benign), according to the "enable" parameter.
**
** Most faults are hard. In other words, most faults cause
** an error to be propagated back up to the application interface.
@ -181,56 +48,11 @@ int sqlite3FaultPending(int id){
** 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++;
}
memfault_is_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--;
}
memfault_is_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;
}
#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */

View File

@ -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.453 2008/06/19 18:17:50 danielk1977 Exp $
** $Id: main.c,v 1.454 2008/06/20 11:05:38 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -1763,6 +1763,7 @@ int sqlite3_test_control(int op, ...){
va_list ap;
va_start(ap, op);
switch( op ){
#if 0
/*
** sqlite3_test_control(FAULT_CONFIG, fault_id, nDelay, nRepeat)
**
@ -1827,6 +1828,7 @@ int sqlite3_test_control(int op, ...){
rc = sqlite3FaultsimInstall(isInstall);
break;
}
#endif
/*
** Save the current state of the PRNG.

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.718 2008/06/19 18:17:50 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.719 2008/06/20 11:05:38 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -2203,30 +2203,18 @@ CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
#define SQLITE_FAULTINJECTOR_COUNT 1
/*
** The interface to the fault injector subsystem. If the fault injector
** mechanism is disabled at compile-time then set up macros so that no
** unnecessary code is generated.
** The interface to the code in fault.c used for identifying "benign"
** malloc failures. This is only present if SQLITE_OMIT_BUILTIN_TEST
** is not defined.
*/
#ifndef SQLITE_OMIT_BUILTIN_TEST
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);
int sqlite3FaultIsBenign(void);
#else
# define sqlite3FaultConfig(A,B,C)
# define sqlite3FaultFailures(A) 0
# define sqlite3FaultBenignFailures(A) 0
# define sqlite3FaultPending(A) (-1)
# define sqlite3FaultBeginBenign(A)
# define sqlite3FaultEndBenign(A)
# define sqlite3FaultStep(A) 0
#define sqlite3FaultBeginBenign()
#define sqlite3FaultEndBenign()
#endif
#define IN_INDEX_ROWID 1
#define IN_INDEX_EPH 2

View File

@ -13,7 +13,7 @@
** 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 $
** $Id: test_malloc.c,v 1.27 2008/06/20 11:05:38 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -21,6 +21,192 @@
#include <string.h>
#include <assert.h>
/*
** This structure is used to encapsulate the global state variables used
** by malloc() fault simulation.
*/
static struct MemFault {
int iCountdown; /* Number of pending successes before 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 */
int isInstalled; /* True if the fault simulation layer is installed */
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( sqlite3FaultIsBenign()>0 ){
memfault.nBenign++;
}
memfault.nRepeat--;
if( memfault.nRepeat<=0 ){
memfault.enable = 0;
}
return 1;
}
/*
** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
** logic.
*/
static void *faultsimMalloc(int n){
void *p = 0;
if( !faultsimStep() ){
p = memfault.m.xMalloc(n);
}
return p;
}
/*
** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
** logic.
*/
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 the malloc failure simulation. After
** calling this routine, the next nDelay mallocs will succeed, followed
** by a block of nRepeat failures, after which malloc() calls will begin
** to succeed again.
*/
static void faultsimConfig(int nDelay, int nRepeat){
memfault.iCountdown = nDelay;
memfault.nRepeat = nRepeat;
memfault.nBenign = 0;
memfault.nFail = 0;
memfault.enable = nDelay>=0;
}
/*
** Return the number of faults (both hard and benign faults) that have
** occurred since the injector was last configured.
*/
static int faultsimFailures(void){
return memfault.nFail;
}
/*
** Return the number of benign faults that have occurred since the
** injector was last configured.
*/
static int faultsimBenignFailures(void){
return memfault.nBenign;
}
/*
** Return the number of successes that will occur before the next failure.
** If no failures are scheduled, return -1.
*/
static int faultsimPending(void){
if( memfault.enable ){
return memfault.iCountdown;
}else{
return -1;
}
}
/*
** Add or remove the fault-simulation layer using sqlite3_config(). If
** the argument is non-zero, the
*/
static int faultsimInstall(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;
install = (install ? 1 : 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;
}
#ifdef SQLITE_TEST
/*
** This function is implemented in test1.c. Returns a pointer to a static
** buffer containing the symbolic SQLite error code that corresponds to
** the least-significant 8-bits of the integer passed as an argument.
** For example:
**
** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
*/
const char *sqlite3TestErrorName(int);
/*
@ -130,7 +316,6 @@ static int test_realloc(
return TCL_OK;
}
/*
** Usage: sqlite3_free PRIOR
**
@ -439,13 +624,10 @@ static int test_memdebug_fail(
}
}
sqlite3_test_control(-12345); /* Just to stress the test_control interface */
nBenign = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES,
SQLITE_FAULTINJECTOR_MALLOC);
nFail = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_FAILURES,
SQLITE_FAULTINJECTOR_MALLOC);
sqlite3_test_control(SQLITE_TESTCTRL_FAULT_CONFIG,
SQLITE_FAULTINJECTOR_MALLOC, iFail, nRepeat);
nBenign = faultsimBenignFailures();
nFail = faultsimFailures();
faultsimConfig(iFail, nRepeat);
if( pBenignCnt ){
Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0);
}
@ -471,8 +653,7 @@ static int test_memdebug_pending(
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
nPending = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_PENDING,
SQLITE_FAULTINJECTOR_MALLOC);
nPending = faultsimPending();
Tcl_SetObjResult(interp, Tcl_NewIntObj(nPending));
return TCL_OK;
}
@ -801,7 +982,7 @@ static int test_install_malloc_faultsim(
if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){
return TCL_ERROR;
}
rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, isInstall);
rc = faultsimInstall(isInstall);
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
return TCL_OK;
}
@ -840,3 +1021,4 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
}
return TCL_OK;
}
#endif