From 643167ff21ce008806a5afc54edec08887d685f2 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 22 Jan 2008 21:30:53 +0000 Subject: [PATCH] Add the fault injector module in fault.c. Use it as a basis for memory allocation failure testing. (CVS 4742) FossilOrigin-Name: 1a335e180183b414fcc3510ce28b98b21cd134a6 --- Makefile.in | 8 ++- main.mk | 3 +- manifest | 45 +++++++------ manifest.uuid | 2 +- src/fault.c | 147 +++++++++++++++++++++++++++++++++++++++++ src/hash.c | 7 +- src/main.c | 6 +- src/mem2.c | 123 +--------------------------------- src/pager.c | 5 +- src/sqliteInt.h | 53 +++++++++------ src/test1.c | 33 +-------- src/test8.c | 9 ++- src/test_config.c | 8 ++- src/test_malloc.c | 33 +++++---- src/vdbe.c | 4 +- src/vdbeInt.h | 2 +- src/vdbeapi.c | 4 +- src/vdbemem.c | 13 +--- test/malloc_common.tcl | 5 +- tool/mksqlite3c.tcl | 1 + 20 files changed, 264 insertions(+), 247 deletions(-) create mode 100644 src/fault.c diff --git a/Makefile.in b/Makefile.in index 9076de78a3..6e01c4c269 100644 --- a/Makefile.in +++ b/Makefile.in @@ -122,7 +122,8 @@ TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1 # LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btmutex.lo btree.lo build.lo \ callback.lo complete.lo date.lo \ - delete.lo expr.lo func.lo hash.lo journal.lo insert.lo loadext.lo \ + delete.lo expr.lo fault.lo func.lo \ + hash.lo journal.lo insert.lo loadext.lo \ main.lo malloc.lo mem1.lo mem2.lo mem3.lo mem4.lo mutex.lo \ mutex_os2.lo mutex_unix.lo mutex_w32.lo \ opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \ @@ -148,6 +149,7 @@ SRC = \ $(TOP)/src/date.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ + $(TOP)/src/fault.c \ $(TOP)/src/func.c \ $(TOP)/src/hash.c \ $(TOP)/src/hash.h \ @@ -230,6 +232,7 @@ TESTSRC = \ $(TOP)/src/pragma.c \ $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ + $(TOP)/src/random.c \ $(TOP)/src/select.c \ $(TOP)/src/test1.c \ $(TOP)/src/test2.c \ @@ -384,6 +387,9 @@ delete.lo: $(TOP)/src/delete.c $(HDR) expr.lo: $(TOP)/src/expr.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/expr.c +fault.lo: $(TOP)/src/fault.c $(HDR) + $(LTCOMPILE) -c $(TOP)/src/fault.c + func.lo: $(TOP)/src/func.c $(HDR) $(LTCOMPILE) -c $(TOP)/src/func.c diff --git a/main.mk b/main.mk index db0807d7f9..5b1fe53728 100644 --- a/main.mk +++ b/main.mk @@ -50,7 +50,7 @@ TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src # LIBOBJ+= alter.o analyze.o attach.o auth.o btmutex.o btree.o build.o \ callback.o complete.o date.o delete.o \ - expr.o func.o hash.o insert.o journal.o loadext.o \ + expr.o fault.o func.o hash.o insert.o journal.o loadext.o \ main.o malloc.o mem1.o mem2.o mem3.o mem4.o mutex.o mutex_os2.o \ mutex_unix.o mutex_w32.o \ opcodes.o os.o os_os2.o os_unix.o os_win.o \ @@ -95,6 +95,7 @@ SRC = \ $(TOP)/src/date.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ + $(TOP)/src/fault.c \ $(TOP)/src/func.c \ $(TOP)/src/hash.c \ $(TOP)/src/hash.h \ diff --git a/manifest b/manifest index aebc2e30c0..93b350a257 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -C Fix\sa\sbug\sintroduced\sby\scheckin\s(4739).\s(CVS\s4741) -D 2008-01-22T19:34:28 +C Add\sthe\sfault\sinjector\smodule\sin\sfault.c.\s\sUse\sit\sas\sa\sbasis\sfor\smemory\nallocation\sfailure\stesting.\s(CVS\s4742) +D 2008-01-22T21:30:53 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 -F Makefile.in 936bcacced594b24b8fdcfc0fc0efc00e15de8a8 +F Makefile.in bc2b5df3e3d0d4b801b824b7ef6dec43812b049b F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 6055d543dbd832b5c0209d6cc787413c1814efdc @@ -64,7 +64,7 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33 F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 -F main.mk b49a8c68baf8c17f72bb1ac78ef183b62f6e3f97 +F main.mk ad3a30d15d88f7d7c58b3c5f6bcee6f917043887 F mkdll.sh 5f8438dcac98e795d7df6529159a1ec566de0183 F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb @@ -93,19 +93,20 @@ F src/date.c 8ce763c68143b1e8fb6f79dcfc8b801853c97017 F src/delete.c 739ccbab8fa7478762bded5c9cc67f16a4d09dbe F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b F src/expr.c 07318c7e5e3062e2d33314f72819ea420b210dc1 +F src/fault.c 049b88b8ba0a1db3240aeaf9695cd08b9a3ba9e1 F src/func.c 8e3d0c59961dc403716767308ee764504179054b -F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c +F src/hash.c 2dc6afe7478a0b739499af360c8863c900ea11a8 F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 F src/insert.c a741d7f0643f52995475d866004eb779578cd773 F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2 F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66 F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35 F src/loadext.c d17a0f760d6866aacf5262f97d8efaaad379cdd7 -F src/main.c f17abe4d28c442749ec892fc466d7e5727af04f2 +F src/main.c de0a4555caa68268c9c804283e9476a4e9aa0c62 F src/malloc.c 60e392a4c12c839517f9b0db7b995f825444fb35 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/mem1.c 6d1a11864963d249c67e72ad5f6533b040333880 -F src/mem2.c a9400e06b41ad5b5189e8416239833212de2c8c7 +F src/mem2.c 607af52ad7593f34934e7e4fa53a364556853d30 F src/mem3.c 9d80034bb004c1bddc28d6befe1ddb044d18deab F src/mem4.c 36ecd536a8b7acfe4cbf011353dae6ea68121e40 F src/mutex.c 3259f62c2429967aee6dc112117a6d2f499ef061 @@ -124,7 +125,7 @@ F src/os_unix.c e4daef7628f690fa2b188af3632fb18f96525946 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c c832d528ea774c7094d887749d71884984c9034c F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c fae75270b4e2b2542b905791087f0c52142974f8 +F src/pager.c d8c2f06c3ce225dd14816cd02f07d7c65aff1f53 F src/pager.h f504f7ae84060fee0416a853e368d3d113c3d6fa F src/parse.y bcc6092d2577f4b525e09928b3ed164965e35c54 F src/pragma.c 2bb8d6882b9a330e041acd05fb6aff5a01bf0a08 @@ -136,27 +137,27 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c ca06cb687c40a8bff6307b5fad41a0e86a0f8558 F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb -F src/sqliteInt.h 9c3384439e402016037115ad143ed0c3adbd1c93 +F src/sqliteInt.h 3b67a79e9b7b9bb1aa5689384ae6524a78070d2c F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4 F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf -F src/test1.c 7e620caf76fe1c9d78e2c062c90f387caab2b40d +F src/test1.c 0040e28115047a50dde02383658f6b25ecbbcb42 F src/test2.c 77b34303883b9d722c65a6879bb0163a400e3789 F src/test3.c 6b49ddb0946907a07210998810807ace51be00a5 F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071 F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4 F src/test6.c f8b34a6ff04937092327798ddf0ab46863535bc5 F src/test7.c acec2256c7c2d279db5a8b5fa1a2a68fcc942c67 -F src/test8.c 6399d2f0561f1f65785c63e94f2cdd36fb248872 +F src/test8.c cab3f576353dfef4877c7cc3b0d0e48acc65c37c F src/test9.c b46c8fe02ac7cca1a7316436d8d38d50c66f4b2f F src/test_async.c 5f21392d66869a4c87dc9153e40d0dc0e085261f F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436 F src/test_btree.c c1308ba0b88ab577fa56c9e493a09829dfcded9c -F src/test_config.c fd6ba4c62dd943e794f00f6ea1e9e32d97bf27f1 +F src/test_config.c c0917656ada90c4aa23c52d1ade39815a930ee18 F src/test_devsym.c 6341971bf1c7769c740501b36bc6192cd975c335 F src/test_hexio.c 1a1cd8324d57585ea86b922f609fa1fbaaf9662d F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 -F src/test_malloc.c 72ceed192f7b229db34a2869ff9285b41a5cb796 +F src/test_malloc.c 7ba7e0c283d22c8b079acc4f73d0a034e9779b26 F src/test_md5.c c107c96637123239c3518b5fbe97a79130f4d32e F src/test_onefile.c 54282b6796d55d7acc489be83b89b8715e7d3756 F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f @@ -169,14 +170,14 @@ F src/update.c 31edd9c9764e80753930bd5f9b43e0edb404636f F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c ca0e3820ce9b0e0ff9bf21f4b726a81163d7b417 F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0 -F src/vdbe.c e7ec3089f1e2ee5ab47b66d2be940f4e8b0029a7 +F src/vdbe.c a3ac8efb7c862ddc3c357ee02612de857cbfd182 F src/vdbe.h 58a7d931ffb704e034b2a725981cfa5bd406fad9 -F src/vdbeInt.h 835e6f0337ce89d705ef9a162338788808adc4b7 -F src/vdbeapi.c cb8c427a3ab646490c83204a98e94eff03ee2e89 +F src/vdbeInt.h 6b4a438198f98a2a2233cc228ed0f120a18628e7 +F src/vdbeapi.c a0cb07fc69553727b5b25c7fb12348528defd99b F src/vdbeaux.c 4a0c75af5366c9114b340c39bea5df76fb26e215 F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120 F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6 -F src/vdbemem.c bb8d4f70e387bd7ff7f4ee349e9f6a9c77cd67c3 +F src/vdbemem.c 79ec9d0d15167baafde2259dddde2a67bd21bcd7 F src/vtab.c 9924e37cf7f5c527aeabb5da025874af505fb91d F src/where.c 0c18a6d88d78886fd5f3c11ef2cf001321acd918 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 @@ -383,7 +384,7 @@ F test/mallocD.test 24c1d07a00e605831d0d627b036bd690b2952416 F test/mallocE.test e15333c394d7c330c8372a7cdf7b0f7c16573082 F test/mallocF.test 6f25bc474f2b29954e5fac274d0e6ed9d86efea5 F test/mallocG.test ac896f96098a30ed0dcc001b6f9243770a463081 -F test/malloc_common.tcl 262c71dd4af005bc3a6b8fe449237688255072a0 +F test/malloc_common.tcl 5c5f7ee985c9ef3480f441efb6329aeefbf9380c F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217 @@ -543,7 +544,7 @@ F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf F tool/mkkeywordhash.c ef93810fc41fb3d3dbacf9a33a29be88ea99ffa9 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x -F tool/mksqlite3c.tcl 21605262fb98d702fbd7c64213c414bd7e60dba4 +F tool/mksqlite3c.tcl 7354a40a96fce512d80be5b5c7f6dce1c61ca070 F tool/mksqlite3internalh.tcl 47737a925fb02fce43e2c0a14b3cc17574a4d44a F tool/omittest.tcl 7d1fdf469e2f4d175f70c36e469db64a1626fabb F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -613,7 +614,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P f47cf3cc5c70ffb70795e9412e6eaeaf044c3559 -R 71bc19b9323f20366a9e6c74fd0d62a0 +P c8394ac24b87707fa7f2e3cb43ad8efb65d2595e +R 21d4a739d8a6a8ab5aa325f6376c5db5 U drh -Z 7ffec562f9d034046208e1f4dd82239a +Z 7682f023570ed6783cc7782294e94c3e diff --git a/manifest.uuid b/manifest.uuid index d53c8f01db..2d0a28a5bb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c8394ac24b87707fa7f2e3cb43ad8efb65d2595e \ No newline at end of file +1a335e180183b414fcc3510ce28b98b21cd134a6 \ No newline at end of file diff --git a/src/fault.c b/src/fault.c new file mode 100644 index 0000000000..4cc369eece --- /dev/null +++ b/src/fault.c @@ -0,0 +1,147 @@ +/* +** 2008 Jan 22 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** 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. +** +************************************************************************* +** 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. +** +** The fault injector is omitted from the code if SQLite is +** compiled with -DSQLITE_OMIT_FAULTINJECTOR=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. +*/ +#include "sqliteInt.h" + +#ifndef SQLITE_OMIT_FAULTINJECTOR + +/* +** 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 */ + u8 benign; /* Ture 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=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=0 && id=0 && id=0 && id=0 && id0 ){ + aFault[id].iCountdown--; + return 0; + } + sqlite3Fault(); + aFault[id].nFail++; + if( aFault[id].benign ){ + aFault[id].nBenign++; + } + aFault[id].nRepeat--; + if( aFault[id].nRepeat<=0 ){ + aFault[id].enable = 0; + } + return 1; +} + +#endif /* SQLITE_OMIT_FAULTINJECTOR */ diff --git a/src/hash.c b/src/hash.c index a88d16b06b..9a91e85e2b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -12,7 +12,7 @@ ** This is the implementation of generic hash-tables ** used in SQLite. ** -** $Id: hash.c,v 1.24 2007/09/04 14:31:47 danielk1977 Exp $ +** $Id: hash.c,v 1.25 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteInt.h" #include @@ -228,9 +228,10 @@ static void rehash(Hash *pH, int new_size){ ** is benign (since failing to resize a hash table is a performance ** hit only, not a fatal error). */ - sqlite3MallocBenignFailure(pH->htsize>0); - + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, pH->htsize>0); new_ht = (struct _ht *)sqlite3MallocZero( new_size*sizeof(struct _ht) ); + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0); + if( new_ht==0 ) return; if( pH->ht ) sqlite3_free(pH->ht); pH->ht = new_ht; diff --git a/src/main.c b/src/main.c index c123eb95e4..7fa01c2e81 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.411 2008/01/22 14:50:17 drh Exp $ +** $Id: main.c,v 1.412 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteInt.h" #include @@ -252,7 +252,7 @@ void sqlite3RollbackAll(sqlite3 *db){ int i; int inTrans = 0; assert( sqlite3_mutex_held(db->mutex) ); - sqlite3MallocEnterBenignBlock(1); /* Enter benign region */ + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1); for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){ @@ -263,7 +263,7 @@ void sqlite3RollbackAll(sqlite3 *db){ } } sqlite3VtabRollback(db); - sqlite3MallocLeaveBenignBlock(); /* Leave benign region */ + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0); if( db->flags&SQLITE_InternChanges ){ sqlite3ExpirePreparedStatements(db); diff --git a/src/mem2.c b/src/mem2.c index 69a641a858..0c99c63e58 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.18 2007/11/29 18:36:49 drh Exp $ +** $Id: mem2.c,v 1.19 2008/01/22 21:30:53 drh Exp $ */ /* @@ -136,18 +136,6 @@ static struct { int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */ char zTitle[100]; /* The title text */ - /* - ** These values are used to simulate malloc failures. When - ** iFail is 1, simulate a malloc failures and reset the value - ** to iReset. - */ - int iFail; /* Decrement and fail malloc when this is 1 */ - int iReset; /* When malloc fails set iiFail to this value */ - int iFailCnt; /* Number of failures */ - int iBenignFailCnt; /* Number of benign failures */ - int iNextIsBenign; /* True if the next call to malloc may fail benignly */ - int iIsBenign; /* All malloc calls may fail benignly */ - /* ** sqlite3MallocDisallow() increments the following counter. ** sqlite3MallocAllow() decrements it. @@ -255,17 +243,6 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ return p; } -/* -** This routine is called once the first time a simulated memory -** failure occurs. The sole purpose of this routine is to provide -** a convenient place to set a debugger breakpoint when debugging -** errors related to malloc() failures. -*/ -static void sqlite3MemsysFailed(void){ - mem.iFailCnt = 0; - mem.iBenignFailCnt = 0; -} - /* ** Allocate nByte bytes of memory. */ @@ -291,21 +268,8 @@ void *sqlite3_malloc(int nByte){ } totalSize = nByte + sizeof(*pHdr) + sizeof(int) + mem.nBacktrace*sizeof(void*) + mem.nTitle; - if( mem.iFail>0 ){ - if( mem.iFail==1 ){ - p = 0; - mem.iFail = mem.iReset; - if( mem.iFailCnt==0 ){ - sqlite3MemsysFailed(); /* A place to set a breakpoint */ - } - mem.iFailCnt++; - if( mem.iNextIsBenign || mem.iIsBenign ){ - mem.iBenignFailCnt++; - } - }else{ - p = malloc(totalSize); - mem.iFail--; - } + if( sqlite3FaultStep(SQLITE_FAULTINJECTOR_MALLOC) ){ + p = 0; }else{ p = malloc(totalSize); if( p==0 ){ @@ -350,7 +314,6 @@ void *sqlite3_malloc(int nByte){ } sqlite3_mutex_leave(mem.mutex); } - mem.iNextIsBenign = 0; return p; } @@ -489,85 +452,5 @@ void sqlite3_memdebug_dump(const char *zFilename){ fclose(out); } -/* -** This routine is used to simulate malloc failures. -** -** After calling this routine, there will be iFail successful -** memory allocations and then a failure. If iRepeat is 1 -** all subsequent memory allocations will fail. If iRepeat is -** 0, only a single allocation will fail. If iRepeat is negative -** then the previous setting for iRepeat is unchanged. -** -** Each call to this routine overrides the previous. To disable -** the simulated allocation failure mechanism, set iFail to -1. -** -** This routine returns the number of simulated failures that have -** occurred since the previous call. -*/ -int sqlite3_memdebug_fail(int iFail, int iRepeat, int *piBenign){ - int n = mem.iFailCnt; - if( piBenign ){ - *piBenign = mem.iBenignFailCnt; - } - mem.iFail = iFail+1; - if( iRepeat>=0 ){ - mem.iReset = iRepeat; - } - mem.iFailCnt = 0; - mem.iBenignFailCnt = 0; - return n; -} - -int sqlite3_memdebug_pending(){ - return (mem.iFail-1); -} - -/* -** The following three functions are used to indicate to the test -** infrastructure which malloc() calls may fail benignly without -** affecting functionality. This can happen when resizing hash tables -** (failing to resize a hash-table is a performance hit, but not an -** error) or sometimes during a rollback operation. -** -** If the argument is true, sqlite3MallocBenignFailure() indicates that the -** next call to allocate memory may fail benignly. -** -** If sqlite3MallocEnterBenignBlock() is called with a non-zero argument, -** then all memory allocations requested before the next call to -** sqlite3MallocLeaveBenignBlock() may fail benignly. -*/ -void sqlite3MallocBenignFailure(int isBenign){ - if( isBenign ){ - mem.iNextIsBenign = 1; - } -} -void sqlite3MallocEnterBenignBlock(int isBenign){ - if( isBenign ){ - mem.iIsBenign = 1; - } -} -void sqlite3MallocLeaveBenignBlock(){ - mem.iIsBenign = 0; -} - -/* -** The following two routines are used to assert that no memory -** allocations occur between one call and the next. The use of -** these routines does not change the computed results in any way. -** These routines are like asserts. -*/ -void sqlite3MallocDisallow(void){ - assert( mem.mutex!=0 ); - sqlite3_mutex_enter(mem.mutex); - mem.disallow++; - sqlite3_mutex_leave(mem.mutex); -} -void sqlite3MallocAllow(void){ - assert( mem.mutex ); - sqlite3_mutex_enter(mem.mutex); - assert( mem.disallow>0 ); - mem.disallow--; - sqlite3_mutex_leave(mem.mutex); -} #endif /* SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */ diff --git a/src/pager.c b/src/pager.c index 13b0b6d399..e7e38953e7 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.403 2008/01/21 13:04:35 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.404 2008/01/22 21:30:53 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -699,8 +699,9 @@ static void pager_resize_hash_table(Pager *pPager, int N){ PgHdr **aHash, *pPg; assert( N>0 && (N&(N-1))==0 ); pagerLeave(pPager); - sqlite3MallocBenignFailure((int)pPager->aHash); + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, pPager->aHash!=0); aHash = sqlite3MallocZero( sizeof(aHash[0])*N ); + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0); pagerEnter(pPager); if( aHash==0 ){ /* Failure to rehash is not an error. It is only a performance hit. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 943e396318..1ba3b8de8a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.652 2008/01/18 14:08:24 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.653 2008/01/22 21:30:53 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1976,26 +1976,6 @@ void sqlite3Parser(void*, int, Token, Parse*); int sqlite3Utf8To8(unsigned char*); #endif -/* -** The MallocDisallow() and MallocAllow() routines are like asserts. -** Call them around a section of code that you do not expect to do -** any memory allocation. -*/ -#ifdef SQLITE_MEMDEBUG - void sqlite3MallocDisallow(void); - void sqlite3MallocAllow(void); - void sqlite3MallocBenignFailure(int); - void sqlite3MallocEnterBenignBlock(int isBenign); - void sqlite3MallocLeaveBenignBlock(); -#else -# define sqlite3MallocDisallow() -# define sqlite3MallocAllow() -# define sqlite3MallocBenignFailure(x) -# define sqlite3MallocEnterBenignBlock(x); -# define sqlite3MallocLeaveBenignBlock(); -#endif - - #ifdef SQLITE_OMIT_VIRTUALTABLE # define sqlite3VtabClear(X) # define sqlite3VtabSync(X,Y) (Y) @@ -2023,6 +2003,37 @@ int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, int, const char*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); + +/* +** Available fault injectors. Should be numbered beginning with 0. +*/ +#define SQLITE_FAULTINJECTOR_MALLOC 0 +#define SQLITE_FAULTINJECTOR_SAFETY 1 +#define SQLITE_FAULTINJECTOR_COUNT 2 + +/* +** 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. +*/ +#ifndef SQLITE_OMIT_FAULTINJECTOR + void sqlite3FaultConfig(int,int,int); + int sqlite3FaultFailures(int); + int sqlite3FaultBenignFailures(int); + int sqlite3FaultPending(int); + void sqlite3FaultBenign(int,int); + int sqlite3FaultStep(int); +#else +# define sqlite3FaultConfig(A,B,C) +# define sqlite3FaultFailures(A) 0 +# define sqlite3FaultBenignFailures(A) 0 +# define sqlite3FaultPending(A) (-1) +# define sqlite3FaultBenign(A,B) +# define sqlite3FaultStep(A) 0 +#endif + + + #define IN_INDEX_ROWID 1 #define IN_INDEX_EPH 2 #define IN_INDEX_INDEX 3 diff --git a/src/test1.c b/src/test1.c index 543021c880..277489241b 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.285 2008/01/22 14:50:17 drh Exp $ +** $Id: test1.c,v 1.286 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -4095,35 +4095,6 @@ static int test_soft_heap_limit( return TCL_OK; } -/* -** Usage: sqlite3_clear_tsd_memdebug -** -** Clear all of the MEMDEBUG information out of thread-specific data. -** This will allow it to be deallocated. -*/ -static int test_clear_tsd_memdebug( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - return TCL_OK; -} - -/* -** Usage: sqlite3_tsd_release -** -** Call sqlite3ReleaseThreadData. -*/ -static int test_tsd_release( - void * clientData, - Tcl_Interp *interp, - int objc, - Tcl_Obj *CONST objv[] -){ - return TCL_OK; -} - /* ** Usage: sqlite3_thread_cleanup ** @@ -4469,8 +4440,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, - { "sqlite3_clear_tsd_memdebug", test_clear_tsd_memdebug, 0}, - { "sqlite3_tsd_release", test_tsd_release, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, diff --git a/src/test8.c b/src/test8.c index 5cbcf533e4..944ac686ef 100644 --- a/src/test8.c +++ b/src/test8.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test8.c,v 1.58 2007/12/13 21:54:11 drh Exp $ +** $Id: test8.c,v 1.59 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -1021,8 +1021,11 @@ static int echoSync(sqlite3_vtab *tab){ return rc; } static int echoCommit(sqlite3_vtab *tab){ - sqlite3MallocBenignFailure(1); - return echoTransactionCall(tab, "xCommit"); + int rc; + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1); + rc = echoTransactionCall(tab, "xCommit"); + sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0); + return rc; } static int echoRollback(sqlite3_vtab *tab){ return echoTransactionCall(tab, "xRollback"); diff --git a/src/test_config.c b/src/test_config.c index aa769e6d26..4f44281224 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -16,7 +16,7 @@ ** The focus of this file is providing the TCL testing layer ** access to compile-time constants. ** -** $Id: test_config.c,v 1.16 2007/10/19 17:47:25 drh Exp $ +** $Id: test_config.c,v 1.17 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteLimit.h" @@ -205,6 +205,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "explain", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_OMIT_FAULTINJECTOR + Tcl_SetVar2(interp, "sqlite_options", "faultinjector", "0", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "faultinjector", "1", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_FLOATING_POINT Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/test_malloc.c b/src/test_malloc.c index 5b777f7d81..237cb96aaf 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.9 2007/10/19 17:47:25 drh Exp $ +** $Id: test_malloc.c,v 1.10 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -349,12 +349,12 @@ static int test_memdebug_dump( ** ** where options are: ** -** -repeat +** -repeat ** -benigncnt ** ** Arrange for a simulated malloc() failure after COUNTER successes. -** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is -** 0 then only a single failure occurs. +** If a repeat count is specified, the fault is repeated that many +** times. ** ** Each call to this routine overrides the prior counter value. ** This routine returns the number of simulated failures that have @@ -370,9 +370,9 @@ static int test_memdebug_fail( ){ int ii; int iFail; - int iRepeat = -1; + int nRepeat = 1; Tcl_Obj *pBenignCnt = 0; - + int nBenign; int nFail = 0; if( objc<2 ){ @@ -390,7 +390,7 @@ static int test_memdebug_fail( if( ii==(objc-1) ){ zErr = "option requires an argument: "; }else{ - if( Tcl_GetIntFromObj(interp, objv[ii+1], &iRepeat) ){ + if( Tcl_GetIntFromObj(interp, objv[ii+1], &nRepeat) ){ return TCL_ERROR; } } @@ -410,16 +410,12 @@ static int test_memdebug_fail( } } -#ifdef SQLITE_MEMDEBUG - { - extern int sqlite3_memdebug_fail(int,int,int*); - int iBenignCnt; - nFail = sqlite3_memdebug_fail(iFail, iRepeat, &iBenignCnt); - if( pBenignCnt ){ - Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(iBenignCnt), 0); - } + nBenign = sqlite3FaultBenignFailures(SQLITE_FAULTINJECTOR_MALLOC); + nFail = sqlite3FaultFailures(SQLITE_FAULTINJECTOR_MALLOC); + sqlite3FaultConfig(SQLITE_FAULTINJECTOR_MALLOC, iFail, nRepeat); + if( pBenignCnt ){ + Tcl_ObjSetVar2(interp, pBenignCnt, 0, Tcl_NewIntObj(nBenign), 0); } -#endif Tcl_SetObjResult(interp, Tcl_NewIntObj(nFail)); return TCL_OK; } @@ -444,8 +440,9 @@ static int test_memdebug_pending( #ifdef SQLITE_MEMDEBUG { - extern int sqlite3_memdebug_pending(); - Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_pending())); + Tcl_SetObjResult(interp, + Tcl_NewIntObj(sqlite3FaultPending(SQLITE_FAULTINJECTOR_MALLOC)) + ); } #endif return TCL_OK; diff --git a/src/vdbe.c b/src/vdbe.c index cefc0ba01f..a827115b97 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.703 2008/01/21 16:22:46 drh Exp $ +** $Id: vdbe.c,v 1.704 2008/01/22 21:30:53 drh Exp $ */ #include "sqliteInt.h" #include @@ -948,7 +948,7 @@ case OP_SCopy: { pOut = &p->aMem[pOp->p2]; assert( pOut!=pIn1 ); if( pOp->opcode==OP_Move ){ - rc = sqlite3VdbeMemMove(pOut, pIn1); + sqlite3VdbeMemMove(pOut, pIn1); }else{ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); if( pOp->opcode==OP_Copy ){ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 094867fa6d..d1377bdd89 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -377,7 +377,7 @@ int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeMemTooBig(Mem*); int sqlite3VdbeMemCopy(Mem*, const Mem*); void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); -int sqlite3VdbeMemMove(Mem*, Mem*); +void sqlite3VdbeMemMove(Mem*, Mem*); int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); void sqlite3VdbeMemSetInt64(Mem*, i64); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index ae9af1674c..7d44fb158c 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1041,9 +1041,7 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ } sqlite3_mutex_enter(pTo->db->mutex); for(i=0; rc==SQLITE_OK && inVar; i++){ - sqlite3MallocDisallow(); - rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); - sqlite3MallocAllow(); + sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]); } sqlite3_mutex_leave(pTo->db->mutex); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); diff --git a/src/vdbemem.c b/src/vdbemem.c index c2631c970c..0449d52f13 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -542,12 +542,9 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ ** Transfer the contents of pFrom to pTo. Any existing value in pTo is ** freed. If pFrom contains ephemeral data, a copy is made. ** -** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM -** might be returned if pFrom held ephemeral data and we were unable -** to allocate enough space to make a copy. +** pFrom contains an SQL NULL when this routine returns. */ -int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ - int rc; +void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ assert( pFrom->db==0 || sqlite3_mutex_held(pFrom->db->mutex) ); assert( pTo->db==0 || sqlite3_mutex_held(pTo->db->mutex) ); assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db ); @@ -560,12 +557,6 @@ int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ } pFrom->flags = MEM_Null; pFrom->xDel = 0; - if( 0 /* pTo->flags & MEM_Ephem */ ){ - rc = sqlite3VdbeMemMakeWriteable(pTo); - }else{ - rc = SQLITE_OK; - } - return rc; } /* diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index f06dbbe84a..840678c045 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -12,7 +12,7 @@ # This file contains common code used by many different malloc tests # within the test suite. # -# $Id: malloc_common.tcl,v 1.11 2008/01/18 17:03:33 drh Exp $ +# $Id: malloc_common.tcl,v 1.12 2008/01/22 21:30:53 drh Exp $ # If we did not compile with malloc testing enabled, then do nothing. # @@ -63,7 +63,7 @@ proc do_malloc_test {tn args} { } save_prng_state - foreach ::iRepeat {0 1} { + foreach ::iRepeat {0 10000000} { set ::go 1 for {set ::n $start} {$::go && $::n <= $end} {incr ::n} { @@ -125,6 +125,7 @@ proc do_malloc_test {tn args} { # set isFail [catch $::mallocbody msg] set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign] + # puts -nonewline " (isFail=$isFail nFail=$nFail nBenign=$nBenign) " # If one or more mallocs failed, run this loop body again. # diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index d99745ca10..6d98790044 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -201,6 +201,7 @@ foreach file { date.c os.c + fault.c mem1.c mem2.c mem3.c