1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-21 09:00:59 +03:00

Repurpose the SQLITE_TESTCTRL_FAULT_INSTALL test-control to register a

callback to be invoked by sqlite3FaultSim().  That test-control has been
unused since 2008-06-20 and was never used in any official release.

FossilOrigin-Name: 0d43a7ad9abe821e33e0bf83a997aa4461b1e3f2
This commit is contained in:
drh
2014-05-16 14:17:01 +00:00
parent a5e2b50d0a
commit c007f61bb0
8 changed files with 171 additions and 20 deletions

View File

@@ -173,15 +173,22 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* isMutexInit */
0, /* isMallocInit */
0, /* isPCacheInit */
0, /* pInitMutex */
0, /* nRefInitMutex */
0, /* pInitMutex */
0, /* xLog */
0, /* pLogArg */
0, /* bLocaltimeFault */
#ifdef SQLITE_ENABLE_SQLLOG
0, /* xSqllog */
0 /* pSqllogArg */
0, /* pSqllogArg */
#endif
#ifdef SQLITE_VDBE_COVERAGE
0, /* xVdbeBranch */
0, /* pVbeBranchArg */
#endif
#ifndef SQLITE_OMIT_BUILTIN_TEST
0, /* xTestCallback */
#endif
0 /* bLocaltimeFault */
};
/*

View File

@@ -3114,6 +3114,23 @@ int sqlite3_test_control(int op, ...){
break;
}
/*
** sqlite3_test_control(FAULT_INSTALL, xCallback)
**
** Arrange to invoke xCallback() whenever sqlite3FaultSim() is called,
** if xCallback is not NULL.
**
** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0)
** is called immediately after installing the new callback and the return
** value from sqlite3FaultSim(0) becomes the return from
** sqlite3_test_control().
*/
case SQLITE_TESTCTRL_FAULT_INSTALL: {
sqlite3Config.xTestCallback = va_arg(ap, int(*)(int));
rc = sqlite3FaultSim(0);
break;
}
/*
** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd)
**

View File

@@ -2709,11 +2709,10 @@ struct Sqlite3Config {
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 */
sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */
void (*xLog)(void*,int,const char*); /* Function for logging */
void *pLogArg; /* First argument to xLog() */
int bLocaltimeFault; /* True to fail localtime() calls */
#ifdef SQLITE_ENABLE_SQLLOG
void(*xSqllog)(void*,sqlite3*,const char*, int);
void *pSqllogArg;
@@ -2725,6 +2724,10 @@ struct Sqlite3Config {
void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
void *pVdbeBranchArg; /* 1st argument */
#endif
#ifndef SQLITE_OMIT_BUILTIN_TEST
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
int bLocaltimeFault; /* True to fail localtime() calls */
};
/*
@@ -3026,6 +3029,12 @@ int sqlite3ParseUri(const char*,const char*,unsigned int*,
Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
int sqlite3CodeOnce(Parse *);
#ifdef SQLITE_OMIT_BUILTIN_TEST
# define sqlite3FaultSim(X) SQLITE_OK
#else
int sqlite3FaultSim(int);
#endif
Bitvec *sqlite3BitvecCreate(u32);
int sqlite3BitvecTest(Bitvec*, u32);
int sqlite3BitvecSet(Bitvec*, u32);

View File

@@ -568,7 +568,90 @@ static int testPendingByte(
rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
}
}
/*
** The sqlite3FaultSim() callback:
*/
static Tcl_Interp *faultSimInterp = 0;
static int faultSimScriptSize = 0;
static char *faultSimScript;
static int faultSimCallback(int x){
char zInt[30];
int i;
int isNeg;
int rc;
if( x==0 ){
memcpy(faultSimScript+faultSimScriptSize, "0", 2);
}else{
/* Convert x to text without using any sqlite3 routines */
if( x<0 ){
isNeg = 1;
x = -x;
}else{
isNeg = 0;
}
zInt[sizeof(zInt)-1] = 0;
for(i=sizeof(zInt)-2; i>0 && x>0; i--, x /= 10){
zInt[i] = (x%10) + '0';
}
if( isNeg ) zInt[i--] = '-';
memcpy(faultSimScript+faultSimScriptSize, zInt+i+1, sizeof(zInt)-i);
}
rc = Tcl_Eval(faultSimInterp, faultSimScript);
if( rc ){
fprintf(stderr, "fault simulator script failed: [%s]", faultSimScript);
rc = SQLITE_ERROR;
}else{
rc = atoi(Tcl_GetStringResult(faultSimInterp));
}
Tcl_ResetResult(faultSimInterp);
return rc;
}
/*
** sqlite3_test_control_fault_install SCRIPT
**
** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim()
** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the
** empty string, cancel the sqlite3FaultSim() callback.
*/
static int faultInstallCmd(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
const char *zScript;
int nScript;
int rc;
if( argc!=1 && argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" SCRIPT\"", (void*)0);
}
zScript = argc==2 ? argv[1] : "";
nScript = (int)strlen(zScript);
if( faultSimScript ){
free(faultSimScript);
faultSimScript = 0;
}
if( nScript==0 ){
rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, 0);
}else{
faultSimScript = malloc( nScript+100 );
if( faultSimScript==0 ){
Tcl_AppendResult(interp, "out of memory", (void*)0);
return SQLITE_ERROR;
}
memcpy(faultSimScript, zScript, nScript);
faultSimScript[nScript] = ' ';
faultSimScriptSize = nScript+1;
faultSimInterp = interp;
rc = sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL, faultSimCallback);
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
/*
** sqlite3BitvecBuiltinTest SIZE PROGRAM
@@ -638,7 +721,8 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
{ "fake_big_file", (Tcl_CmdProc*)fake_big_file },
#endif
{ "sqlite3BitvecBuiltinTest",(Tcl_CmdProc*)testBitvecBuiltinTest },
{ "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
{ "sqlite3_test_control_pending_byte", (Tcl_CmdProc*)testPendingByte },
{ "sqlite3_test_control_fault_install", (Tcl_CmdProc*)faultInstallCmd },
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){

View File

@@ -31,6 +31,24 @@ void sqlite3Coverage(int x){
}
#endif
/*
** Give a callback to the test harness that can be used to simulate faults
** in places where it is difficult or expensive to do so purely by means
** of inputs.
**
** The intent of the integer argument is to let the fault simulator know
** which of multiple sqlite3FaultSim() calls has been hit.
**
** Return whatever integer value the test callback returns, or return
** SQLITE_OK if no test callback is installed.
*/
#ifndef SQLITE_OMIT_BUILTIN_TEST
int sqlite3FaultSim(int iTest){
int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback;
return xCallback ? xCallback(iTest) : SQLITE_OK;
}
#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).