]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add tests to check that sqlite recovers from an error in sqlite3_initialize() correctly.
authordan <dan@noemail.net>
Mon, 17 Aug 2009 15:16:19 +0000 (15:16 +0000)
committerdan <dan@noemail.net>
Mon, 17 Aug 2009 15:16:19 +0000 (15:16 +0000)
FossilOrigin-Name: 904a371c6c9d3f20332b37767b06161fa0a78113

main.mk
manifest
manifest.uuid
src/global.c
src/main.c
src/os_unix.c
src/os_win.c
src/sqliteInt.h
src/tclsqlite.c
src/test_init.c [new file with mode: 0644]
test/init.test [new file with mode: 0644]

diff --git a/main.mk b/main.mk
index 3e16eda10b8c1f007008997689e6cc984f855b40..56fbdc66d4c4acdf05d94d85dac16a438d18a32d 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -229,6 +229,7 @@ TESTSRC = \
   $(TOP)/src/test_devsym.c \
   $(TOP)/src/test_func.c \
   $(TOP)/src/test_hexio.c \
+  $(TOP)/src/test_init.c \
   $(TOP)/src/test_journal.c \
   $(TOP)/src/test_malloc.c \
   $(TOP)/src/test_md5.c \
index 5af92176a54498039fda99725583b1dc690b8f85..7bc0effdc8c7eb8cd9f1f65b9f8f645eeb729e40 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,8 +1,5 @@
------BEGIN PGP SIGNED MESSAGE-----
-Hash: SHA1
-
-C Enhanced\sdocumentation\sand\sminor\scode\stweaks\sin\spreparation\sfor\shardening\nthe\ssqlite3_initialize/shutdown\sinterfaces\sagainst\sinitialization\sfailures.
-D 2009-08-17T13:42:30
+C Add\stests\sto\scheck\sthat\ssqlite\srecovers\sfrom\san\serror\sin\ssqlite3_initialize()\scorrectly.
+D 2009-08-17T15:16:19
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 0f7761c5d1c62ae7a841e3393ffaff1fa0f5c00a
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -89,7 +86,7 @@ F ext/rtree/tkt3363.test 6662237ea75bb431cd5d262dfc9535e1023315fc
 F ext/rtree/viewrtree.tcl 09526398dae87a5a87c5aac2b3854dbaf8376869
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
-F main.mk 6272ba6c273b6390602b276dd2b1e4fe71d1049a
+F main.mk 3ae48161d5a76def45cd8fa253b28295f239dd69
 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
 F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
 F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -120,7 +117,7 @@ F src/delete.c dcf07632d8ca3d4086df8b65ea907a47278e6382
 F src/expr.c d069ba1e060f296ea4f18fb85198fafefd00b22f
 F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
 F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
-F src/global.c 263dea92c89956eef9335fe2cf6af8e3fa34646b
+F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32
 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
 F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
 F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
@@ -129,7 +126,7 @@ F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
 F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6
 F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d
 F src/loadext.c 0e88a335665db0b2fb4cece3e49dcb65d832635a
-F src/main.c 6873986c416ce78e8102b5189aef1179053be4e9
+F src/main.c cb283c9e98d50cb14b01d6b736c4336f7bf07189
 F src/malloc.c ae9fef00398ead775630cad97e228d527178eb3a
 F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
 F src/mem1.c e6d5c23941288df8191b8a98c28e3f57771e2270
@@ -148,8 +145,8 @@ F src/os.c 5029ae6c88d1869ad9034008a9531658d53438e4
 F src/os.h fa3f4aa0119ff721a2da4b47ffd74406ac864c05
 F src/os_common.h 8c61457df58f1a4bd5f5adc3e90e01b37bf7afbc
 F src/os_os2.c bed77dc26e3a95ce4a204936b9a1ca6fe612fcc5
-F src/os_unix.c cdb2a08b9ce4aa13b3f7b91d4dd60fb48be9f56a
-F src/os_win.c 6de69d8f51d4bf35484e9be1588089a61569491f
+F src/os_unix.c aea2a5c1c07c47767b0961b670dc647aa4aefc4e
+F src/os_win.c a3e93d1b44a818ce9422e2e588984df1cb7e4819
 F src/pager.c a47be286477ed6c7b9a342dd53d4e4043f29d8c2
 F src/pager.h 11852d044c86cf5a9d6e34171fb0c4fcf1f6265f
 F src/parse.y 6c42631e72a3d14cde2bee85e79409066066d3df
@@ -166,11 +163,11 @@ F src/select.c 67b0778c9585905c8aa75aaa469e76ef3c1d315a
 F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
 F src/sqlite.h.in b309f8f5ecc76fc2d56a32d6563b3636901befb1
 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 6a90791138ba3447572d184d0798c24f3cbbec98
+F src/sqliteInt.h d675e20da30db2c28e7166deb1fc758fb5b29a9a
 F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
 F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
-F src/tclsqlite.c e18e5013dc6bca9f25e6022fbe17ba3ccb821f95
+F src/tclsqlite.c 5eea5025c370d3a91ce0415f9d46f96fdc7aef44
 F src/test1.c 0e882812c94cf35fce30fc25fbf952a33a86d70b
 F src/test2.c 0de743ec8890ca4f09e0bce5d6d5a681f5957fec
 F src/test3.c 2445c2beb5e7a0c91fd8136dc1339ec369a24898
@@ -188,6 +185,7 @@ F src/test_config.c 63d1b08809ca182ee75429573111b44735861c64
 F src/test_devsym.c 9f4bc2551e267ce7aeda195f3897d0f30c5228f4
 F src/test_func.c 26ac62d8ed7a9f45a1e05baffb1c1e55fe2a06f2
 F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
+F src/test_init.c ff7c0e055fb786f5b048df83b6dfb1624851a88b
 F src/test_journal.c dab49b7c47b53242f039c9563b18cafb67ebfe03
 F src/test_loadext.c 97dc8800e46a46ed002c2968572656f37e9c0dd9
 F src/test_malloc.c d054506b095d711e4e5575558dd576a2cbf035a2
@@ -411,6 +409,7 @@ F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
 F test/index3.test 727d55dceb9a4ec36675057bb5becfc265e28ca6
 F test/indexedby.test 946ca2628a521f4ced0520421a0788345abaf3dc
+F test/init.test 5768d2cfeb25df627d42de675ab6201a65c167fe
 F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
@@ -747,14 +746,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
-P 78dfe8321db9debfcd4a7f3daf4223d0cbf23ab9
-R 59b834c230f554631ea111aff633ae3d
-U drh
-Z 14a85d4458d8211ec1ee47b0a57f04f9
------BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.6 (GNU/Linux)
-
-iD8DBQFKiV5JoxKgR168RlERAhxLAJ9VpGZymsNQGLlIzDsn3KQPM4CSYgCfR70O
-KCNsn02bCPSvHz/OQJ5kVZc=
-=CGmi
------END PGP SIGNATURE-----
+P 98c49e6135ae6268a80de88f8b0284f88ef32e1d
+R 403bbd0c163020937b591c0dbd3d7490
+U dan
+Z d3982d3f3fe40cd70ed5dd9628e2f879
index 4fa49fe48ac81e22121776aa46e045ccbea2bab0..592e3a09eb4631248c6b8cc2780619c77674697b 100644 (file)
@@ -1 +1 @@
-98c49e6135ae6268a80de88f8b0284f88ef32e1d
\ No newline at end of file
+904a371c6c9d3f20332b37767b06161fa0a78113
\ No newline at end of file
index 5b5524b0e44901c5d141ce2410ee1d263e6c4e3f..07b133d6fc3a04d87abc6dee622e9647ad2d558b 100644 (file)
@@ -11,8 +11,6 @@
 *************************************************************************
 **
 ** This file contains definitions of global variables and contants.
-**
-** $Id: global.c,v 1.12 2009/02/05 16:31:46 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -156,7 +154,9 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    /* All the rest should always be initialized to zero */
    0,                         /* isInit */
    0,                         /* inProgress */
+   0,                         /* isMutexInit */
    0,                         /* isMallocInit */
+   0,                         /* isPCacheInit */
    0,                         /* pInitMutex */
    0,                         /* nRefInitMutex */
 };
index 05473701d067150809a0cbf4576db8a39cbd5824..fe26386a0bfd9655fbea5dc0a4d7b4d2da78a913 100644 (file)
@@ -124,6 +124,7 @@ int sqlite3_initialize(void){
   */
   pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
   sqlite3_mutex_enter(pMaster);
+  sqlite3GlobalConfig.isMutexInit = 1;
   if( !sqlite3GlobalConfig.isMallocInit ){
     rc = sqlite3MallocInit();
   }
@@ -142,10 +143,9 @@ int sqlite3_initialize(void){
   }
   sqlite3_mutex_leave(pMaster);
 
-  /* If unable to initialize the malloc subsystem, then return early.
-  ** There is little hope of getting SQLite to run if the malloc
-  ** subsystem cannot be initialized.
-  */
+  /* If rc is not SQLITE_OK at this point, then either the malloc
+  ** subsystem could not be initialized or the system failed to allocate
+  ** the pInitMutex mutex. Return an error in either case.  */
   if( rc!=SQLITE_OK ){
     return rc;
   }
@@ -162,8 +162,11 @@ int sqlite3_initialize(void){
     sqlite3GlobalConfig.inProgress = 1;
     memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
     sqlite3RegisterGlobalFunctions();
-    rc = sqlite3PcacheInitialize();
+    if( sqlite3GlobalConfig.isPCacheInit==0 ){
+      rc = sqlite3PcacheInitialize();
+    }
     if( rc==SQLITE_OK ){
+      sqlite3GlobalConfig.isPCacheInit = 1;
       rc = sqlite3_os_init();
     }
     if( rc==SQLITE_OK ){
@@ -219,14 +222,23 @@ int sqlite3_initialize(void){
 */
 int sqlite3_shutdown(void){
   if( sqlite3GlobalConfig.isInit ){
-    sqlite3GlobalConfig.isMallocInit = 0;
-    sqlite3PcacheShutdown();
     sqlite3_os_end();
     sqlite3_reset_auto_extension();
+    sqlite3GlobalConfig.isInit = 0;
+  }
+  if( sqlite3GlobalConfig.isPCacheInit ){
+    sqlite3PcacheShutdown();
+    sqlite3GlobalConfig.isPCacheInit = 0;
+  }
+  if( sqlite3GlobalConfig.isMallocInit ){
     sqlite3MallocEnd();
+    sqlite3GlobalConfig.isMallocInit = 0;
+  }
+  if( sqlite3GlobalConfig.isMutexInit ){
     sqlite3MutexEnd();
-    sqlite3GlobalConfig.isInit = 0;
+    sqlite3GlobalConfig.isMutexInit = 0;
   }
+
   return SQLITE_OK;
 }
 
index bc0f32cde1a443987601f3a6d051c6a86852253e..00bbb538c236fb293174e4f1ad553c536523ef17 100644 (file)
@@ -42,8 +42,6 @@
 **   *  Locking primitives for the proxy uber-locking-method. (MacOSX only)
 **   *  Definitions of sqlite3_vfs objects for all locking methods
 **      plus implementations of sqlite3_os_init() and sqlite3_os_end().
-**
-** $Id: os_unix.c,v 1.254 2009/07/03 12:57:58 drh Exp $
 */
 #include "sqliteInt.h"
 #if SQLITE_OS_UNIX              /* This file is used on unix only */
@@ -5128,6 +5126,13 @@ int sqlite3_os_init(void){
   };
   unsigned int i;          /* Loop counter */
 
+#ifdef SQLITE_TEST
+  /* This block is used by test code only to simulate the effect on sqlite
+  ** of returning an error from within the sqlite3_os_init() function.  */
+  int sqlite3TestFailOsInit(void);
+  if( sqlite3TestFailOsInit() ){ return SQLITE_ERROR; }
+#endif
+
   /* Register all VFSes defined in the aVfs[] array */
   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
     sqlite3_vfs_register(&aVfs[i], i==0);
index 36c93f8d9201415a3d5cbf587d24ae92d750f5de..220b123c8fb77c14310e8a1ebbfb027388e86898 100644 (file)
@@ -11,8 +11,6 @@
 ******************************************************************************
 **
 ** This file contains code that is specific to windows.
-**
-** $Id: os_win.c,v 1.157 2009/08/05 04:08:30 shane Exp $
 */
 #include "sqliteInt.h"
 #if SQLITE_OS_WIN               /* This file is used for windows only */
@@ -1884,6 +1882,14 @@ int sqlite3_os_init(void){
     winCurrentTime,    /* xCurrentTime */
     winGetLastError    /* xGetLastError */
   };
+
+#ifdef SQLITE_TEST
+  /* This block is used by test code only to simulate the effect on sqlite
+  ** of returning an error from within the sqlite3_os_init() function.  */
+  int sqlite3TestFailOsInit(void);
+  if( sqlite3TestFailOsInit() ){ return SQLITE_ERROR; }
+#endif
+
   sqlite3_vfs_register(&winVfs, 1);
   return SQLITE_OK; 
 }
index a737a12c736ca640ec8082365975b6655e0c4760..38a31cbc980d26ba5f3f683f54309a339fbe3889 100644 (file)
@@ -11,7 +11,6 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.898 2009/08/10 03:57:58 shane Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -2310,7 +2309,9 @@ struct Sqlite3Config {
   ** initially be zero, however. */
   int isInit;                       /* True after initialization has finished */
   int inProgress;                   /* True while initialization in progress */
+  int isMutexInit;                  /* True after mutexes are initialized */
   int isMallocInit;                 /* True after malloc is initialized */
+  int isPCacheInit;                 /* True after malloc is initialized */
   sqlite3_mutex *pInitMutex;        /* Mutex used by sqlite3_initialize() */
   int nRefInitMutex;                /* Number of users of pInitMutex */
 };
index d353fc3dd4f8bb19c2164772971818ee39c13677..223a7dfd728d220c9d0d574f9a9cfcf2e50e4fa3 100644 (file)
@@ -11,8 +11,6 @@
 *************************************************************************
 ** A TCL Interface to SQLite.  Append this file to sqlite3.c and
 ** compile the whole thing to build a TCL-enabled version of SQLite.
-**
-** $Id: tclsqlite.c,v 1.242 2009/07/03 22:54:37 drh Exp $
 */
 #include "tcl.h"
 #include <errno.h>
@@ -2849,6 +2847,7 @@ int TCLSH_MAIN(int argc, char **argv){
     extern int Sqlitetest_autoext_Init(Tcl_Interp*);
     extern int Sqlitetest_func_Init(Tcl_Interp*);
     extern int Sqlitetest_hexio_Init(Tcl_Interp*);
+    extern int Sqlitetest_init_Init(Tcl_Interp*);
     extern int Sqlitetest_malloc_Init(Tcl_Interp*);
     extern int Sqlitetest_mutex_Init(Tcl_Interp*);
     extern int Sqlitetestschema_Init(Tcl_Interp*);
@@ -2874,6 +2873,7 @@ int TCLSH_MAIN(int argc, char **argv){
     Sqlitetest_autoext_Init(interp);
     Sqlitetest_func_Init(interp);
     Sqlitetest_hexio_Init(interp);
+    Sqlitetest_init_Init(interp);
     Sqlitetest_malloc_Init(interp);
     Sqlitetest_mutex_Init(interp);
     Sqlitetestschema_Init(interp);
diff --git a/src/test_init.c b/src/test_init.c
new file mode 100644 (file)
index 0000000..a8b8ce0
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+** 2009 August 17
+**
+** 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.
+**
+*************************************************************************
+**
+** The code in this file is used for testing SQLite. It is not part of
+** the source code used in production systems.
+**
+** Specifically, this file tests the effect of errors while initializing
+** the various pluggable sub-systems from within sqlite3_initialize().
+** If an error occurs in sqlite3_initialize() the following should be
+** true:
+**
+**   1) An error code is returned to the user, and
+**   2) A subsequent call to sqlite3_shutdown() calls the shutdown method
+**      of those subsystems that were initialized, and
+**   3) A subsequent call to sqlite3_initialize() attempts to initialize
+**      the remaining, uninitialized, subsystems.
+*/
+
+#include "sqliteInt.h"
+#include <string.h>
+#include <tcl.h>
+
+static struct Wrapped {
+  sqlite3_pcache_methods pcache;
+  sqlite3_mem_methods    mem;
+  sqlite3_mutex_methods  mutex;
+
+  int mem_init;                /* True if mem subsystem is initalized */
+  int mem_fail;                /* True to fail mem subsystem inialization */
+  int mutex_init;              /* True if mutex subsystem is initalized */
+  int mutex_fail;              /* True to fail mutex subsystem inialization */
+  int pcache_init;             /* True if pcache subsystem is initalized */
+  int pcache_fail;             /* True to fail pcache subsystem inialization */
+  int osinit_fail;             /* True to fail OS subsystem inialization */
+} wrapped;
+
+static int wrMemInit(void *pAppData){
+  int rc;
+  if( wrapped.mem_fail ){
+    rc = SQLITE_ERROR;
+  }else{
+    rc = wrapped.mem.xInit(wrapped.mem.pAppData);
+  }
+  if( rc==SQLITE_OK ){
+    wrapped.mem_init = 1;
+  }
+  return rc;
+}
+static void wrMemShutdown(void *pAppData){
+  wrapped.mem.xShutdown(wrapped.mem.pAppData);
+  wrapped.mem_init = 0;
+}
+static void *wrMemMalloc(int n)           {return wrapped.mem.xMalloc(n);}
+static void wrMemFree(void *p)            {wrapped.mem.xFree(p);}
+static void *wrMemRealloc(void *p, int n) {return wrapped.mem.xRealloc(p, n);}
+static int wrMemSize(void *p)             {return wrapped.mem.xSize(p);}
+static int wrMemRoundup(int n)            {return wrapped.mem.xRoundup(n);}
+
+
+static int wrMutexInit(void){
+  int rc;
+  if( wrapped.mutex_fail ){
+    rc = SQLITE_ERROR;
+  }else{
+    rc = wrapped.mutex.xMutexInit();
+  }
+  if( rc==SQLITE_OK ){
+    wrapped.mutex_init = 1;
+  }
+  return rc;
+}
+static int wrMutexEnd(void){
+  wrapped.mutex.xMutexEnd();
+  wrapped.mutex_init = 0;
+  return SQLITE_OK;
+}
+static sqlite3_mutex *wrMutexAlloc(int e){
+  return wrapped.mutex.xMutexAlloc(e);
+}
+static void wrMutexFree(sqlite3_mutex *p){
+  wrapped.mutex.xMutexFree(p);
+}
+static void wrMutexEnter(sqlite3_mutex *p){
+  wrapped.mutex.xMutexEnter(p);
+}
+static int wrMutexTry(sqlite3_mutex *p){
+  return wrapped.mutex.xMutexTry(p);
+}
+static void wrMutexLeave(sqlite3_mutex *p){
+  wrapped.mutex.xMutexLeave(p);
+}
+static int wrMutexHeld(sqlite3_mutex *p){
+  return wrapped.mutex.xMutexHeld(p);
+}
+static int wrMutexNotheld(sqlite3_mutex *p){
+  return wrapped.mutex.xMutexNotheld(p);
+}
+
+
+
+static int wrPCacheInit(void *pArg){
+  int rc;
+  if( wrapped.pcache_fail ){
+    rc = SQLITE_ERROR;
+  }else{
+    rc = wrapped.pcache.xInit(wrapped.pcache.pArg);
+  }
+  if( rc==SQLITE_OK ){
+    wrapped.pcache_init = 1;
+  }
+  return rc;
+}
+static void wrPCacheShutdown(void *pArg){
+  wrapped.pcache.xShutdown(wrapped.pcache.pArg);
+  wrapped.pcache_init = 0;
+}
+
+static sqlite3_pcache *wrPCacheCreate(int a, int b){
+  return wrapped.pcache.xCreate(a, b);
+}  
+static void wrPCacheCachesize(sqlite3_pcache *p, int n){
+  wrapped.pcache.xCachesize(p, n);
+}  
+static int wrPCachePagecount(sqlite3_pcache *p){
+  return wrapped.pcache.xPagecount(p);
+}  
+static void *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){
+  return wrapped.pcache.xFetch(p, a, b);
+}  
+static void wrPCacheUnpin(sqlite3_pcache *p, void *a, int b){
+  wrapped.pcache.xUnpin(p, a, b);
+}  
+static void wrPCacheRekey(sqlite3_pcache *p, void *a, unsigned b, unsigned c){
+  wrapped.pcache.xRekey(p, a, b, c);
+}  
+static void wrPCacheTruncate(sqlite3_pcache *p, unsigned a){
+  wrapped.pcache.xTruncate(p, a);
+}  
+static void wrPCacheDestroy(sqlite3_pcache *p){
+  wrapped.pcache.xDestroy(p);
+}  
+
+static void installInitWrappers(void){
+  sqlite3_mutex_methods mutexmethods = {
+    wrMutexInit,  wrMutexEnd,   wrMutexAlloc,
+    wrMutexFree,  wrMutexEnter, wrMutexTry,
+    wrMutexLeave, wrMutexHeld,  wrMutexNotheld
+  };
+  sqlite3_pcache_methods pcachemethods = {
+    0,
+    wrPCacheInit,      wrPCacheShutdown,  wrPCacheCreate, 
+    wrPCacheCachesize, wrPCachePagecount, wrPCacheFetch,
+    wrPCacheUnpin,     wrPCacheRekey,     wrPCacheTruncate,  
+    wrPCacheDestroy
+  };
+  sqlite3_mem_methods memmethods = {
+    wrMemMalloc,   wrMemFree,    wrMemRealloc,
+    wrMemSize,     wrMemRoundup, wrMemInit,
+    wrMemShutdown,
+    0
+  };
+
+  memset(&wrapped, 0, sizeof(wrapped));
+
+  sqlite3_shutdown();
+  sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex);
+  sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem);
+  sqlite3_config(SQLITE_CONFIG_GETPCACHE, &wrapped.pcache);
+  sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods);
+  sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods);
+  sqlite3_config(SQLITE_CONFIG_PCACHE, &pcachemethods);
+}
+
+static int init_wrapper_install(
+  ClientData clientData, /* Unused */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  int i;
+  installInitWrappers();
+  for(i=1; i<objc; i++){
+    char *z = Tcl_GetString(objv[i]);
+    if( strcmp(z, "mem")==0 ){
+      wrapped.mem_fail = 1;
+    }else if( strcmp(z, "mutex")==0 ){
+      wrapped.mutex_fail = 1;
+    }else if( strcmp(z, "pcache")==0 ){
+      wrapped.pcache_fail = 1;
+    }else if( strcmp(z, "os")==0 ){
+      wrapped.osinit_fail = 1;
+    }else{
+      Tcl_AppendResult(interp, "Unknown argument: \"", z, "\"");
+      return TCL_ERROR;
+    }
+  }
+  return TCL_OK;
+}
+
+static int init_wrapper_uninstall(
+  ClientData clientData, /* Unused */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  if( objc!=1 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "");
+    return TCL_ERROR;
+  }
+
+  memset(&wrapped, 0, sizeof(&wrapped));
+  sqlite3_shutdown();
+  sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex);
+  sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem);
+  sqlite3_config(SQLITE_CONFIG_PCACHE, &wrapped.pcache);
+  return TCL_OK;
+}
+
+static int init_wrapper_clear(
+  ClientData clientData, /* Unused */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  if( objc!=1 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "");
+    return TCL_ERROR;
+  }
+
+  wrapped.mem_fail = 0;
+  wrapped.mutex_fail = 0;
+  wrapped.pcache_fail = 0;
+  wrapped.osinit_fail = 0;
+  return TCL_OK;
+}
+
+static int init_wrapper_query(
+  ClientData clientData, /* Unused */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  Tcl_Obj *pRet;
+
+  if( objc!=1 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "");
+    return TCL_ERROR;
+  }
+
+  pRet = Tcl_NewObj();
+  if( wrapped.mutex_init ){
+    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mutex", -1));
+  }
+  if( wrapped.mem_init ){
+    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mem", -1));
+  }
+  if( wrapped.pcache_init ){
+    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("pcache", -1));
+  }
+  if( sqlite3GlobalConfig.isInit ){
+    Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("os", -1));
+  }
+
+  Tcl_SetObjResult(interp, pRet);
+  return TCL_OK;
+}
+
+int sqlite3TestFailOsInit(void){
+  return (wrapped.mem.xMalloc && wrapped.osinit_fail);
+}
+
+int Sqlitetest_init_Init(Tcl_Interp *interp){
+  static struct {
+     char *zName;
+     Tcl_ObjCmdProc *xProc;
+  } aObjCmd[] = {
+    {"init_wrapper_install",   init_wrapper_install},
+    {"init_wrapper_query",     init_wrapper_query  },
+    {"init_wrapper_uninstall", init_wrapper_uninstall},
+    {"init_wrapper_clear",     init_wrapper_clear}
+  };
+  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;
+}
+
diff --git a/test/init.test b/test/init.test
new file mode 100644 (file)
index 0000000..b68ebbc
--- /dev/null
@@ -0,0 +1,56 @@
+# 2001 September 15
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+db close
+
+foreach {t failed rc started} {
+  1.1 {}       SQLITE_OK    {mutex mem pcache os}
+  1.2 {mutex}  SQLITE_ERROR {}
+  1.3 {mem}    SQLITE_ERROR {mutex}
+  1.4 {pcache} SQLITE_ERROR {mutex mem}
+  1.5 {os}     SQLITE_ERROR {mutex mem pcache}
+} {
+  do_test init-$t.1 {
+    eval init_wrapper_install $failed
+    sqlite3_initialize
+  } $rc
+  do_test init-$t.2 {
+    init_wrapper_query
+  } $started
+  do_test init-$t.3 {
+    sqlite3_shutdown
+    init_wrapper_query
+  } {}
+  do_test init-$t.4 {
+    sqlite3_initialize
+  } $rc
+  do_test init-$t.5 {
+    init_wrapper_query
+  } $started
+  do_test init-$t.6 {
+    init_wrapper_clear
+    sqlite3_initialize
+  } SQLITE_OK
+  do_test init-$t.7 {
+    init_wrapper_query
+  } {mutex mem pcache os}
+  do_test init-$t.8 {
+    init_wrapper_uninstall
+  } {}
+}
+
+autoinstall_test_functions
+finish_test
+