aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <dan@noemail.net>2009-08-17 15:16:19 +0000
committerdan <dan@noemail.net>2009-08-17 15:16:19 +0000
commite1ab2193092623f4f826f9ac73aa05ac494c8982 (patch)
treed04e9edc60acf046539815235c0b0167ab5ec46f /src
parent9ac06509f19101b9b9f563a659761e1ae1c6b78c (diff)
downloadsqlite-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.c4
-rw-r--r--src/main.c28
-rw-r--r--src/os_unix.c9
-rw-r--r--src/os_win.c10
-rw-r--r--src/sqliteInt.h3
-rw-r--r--src/tclsqlite.c4
-rw-r--r--src/test_init.c299
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;
+}
+