diff options
author | dan <dan@noemail.net> | 2009-08-17 15:16:19 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2009-08-17 15:16:19 +0000 |
commit | e1ab2193092623f4f826f9ac73aa05ac494c8982 (patch) | |
tree | d04e9edc60acf046539815235c0b0167ab5ec46f /src | |
parent | 9ac06509f19101b9b9f563a659761e1ae1c6b78c (diff) | |
download | sqlite-e1ab2193092623f4f826f9ac73aa05ac494c8982.tar.gz sqlite-e1ab2193092623f4f826f9ac73aa05ac494c8982.zip |
Add tests to check that sqlite recovers from an error in sqlite3_initialize() correctly.
FossilOrigin-Name: 904a371c6c9d3f20332b37767b06161fa0a78113
Diffstat (limited to 'src')
-rw-r--r-- | src/global.c | 4 | ||||
-rw-r--r-- | src/main.c | 28 | ||||
-rw-r--r-- | src/os_unix.c | 9 | ||||
-rw-r--r-- | src/os_win.c | 10 | ||||
-rw-r--r-- | src/sqliteInt.h | 3 | ||||
-rw-r--r-- | src/tclsqlite.c | 4 | ||||
-rw-r--r-- | src/test_init.c | 299 |
7 files changed, 340 insertions, 17 deletions
diff --git a/src/global.c b/src/global.c index 5b5524b0e..07b133d6f 100644 --- a/src/global.c +++ b/src/global.c @@ -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 */ }; diff --git a/src/main.c b/src/main.c index 05473701d..fe26386a0 100644 --- a/src/main.c +++ b/src/main.c @@ -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; } diff --git a/src/os_unix.c b/src/os_unix.c index bc0f32cde..00bbb538c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -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); diff --git a/src/os_win.c b/src/os_win.c index 36c93f8d9..220b123c8 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -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; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a737a12c7..38a31cbc9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 */ }; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index d353fc3dd..223a7dfd7 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -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 index 000000000..a8b8ce0d5 --- /dev/null +++ b/src/test_init.c @@ -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; +} + |