From ef05f2dfe33bbc7206065d7209e964d070e927b7 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Fri, 20 Jun 2008 11:05:37 +0000 Subject: [PATCH] Move (almost all) malloc failure test logic from fault.c to test_malloc.c. (CVS 5253) FossilOrigin-Name: 4ae21e3419ad7e69dd735ca45fdc5a2de93d1840 --- manifest | 20 ++--- manifest.uuid | 2 +- src/fault.c | 214 ++++------------------------------------------ src/main.c | 4 +- src/sqliteInt.h | 26 ++---- src/test_malloc.c | 206 +++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 233 insertions(+), 239 deletions(-) diff --git a/manifest b/manifest index 528a65dc58..6f6b713946 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 698fac23f6..90058d4533 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62411a6e605ec50d8d61233d753cd2ad65c2218d \ No newline at end of file +4ae21e3419ad7e69dd735ca45fdc5a2de93d1840 \ No newline at end of file diff --git a/src/fault.c b/src/fault.c index c2f9dada8b..54bc810bfe 100644 --- a/src/fault.c +++ b/src/fault.c @@ -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=0 && id0 ); - 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 */ diff --git a/src/main.c b/src/main.c index 825d1ed01f..18b2a2cb3e 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.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 @@ -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. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c5e4471c64..830183d9ba 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 diff --git a/src/test_malloc.c b/src/test_malloc.c index 59a2954f79..0cc4911c52 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.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 #include +/* +** 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