1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Add the --oom option to fuzzershell.

FossilOrigin-Name: 14a9e4a377bf2974f5db148c8f86e2c5ffdfa28d
This commit is contained in:
drh
2015-04-24 23:45:23 +00:00
parent 61a0d6bc55
commit 048810b63b
3 changed files with 154 additions and 63 deletions

View File

@ -71,11 +71,51 @@
** All global variables are gathered into the "g" singleton.
*/
struct GlobalVars {
const char *zArgv0; /* Name of program */
const char *zArgv0; /* Name of program */
sqlite3_mem_methods sOrigMem; /* Original memory methods */
sqlite3_mem_methods sOomMem; /* Memory methods with OOM simulator */
int iOomCntdown; /* Memory fails on 1 to 0 transition */
int nOomFault; /* Increments for each OOM fault */
int bOomOnce; /* Fail just once if true */
int bOomEnable; /* True to enable OOM simulation */
int nOomBrkpt; /* Number of calls to oomFault() */
} g;
/*
** This routine is called when a simulated OOM occurs. It exists as a
** convenient place to set a debugger breakpoint.
*/
static void oomFault(void){
g.nOomBrkpt++;
}
/* Versions of malloc() and realloc() that simulate OOM conditions */
static void *oomMalloc(int nByte){
if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){
g.iOomCntdown--;
if( g.iOomCntdown==0 ){
if( g.nOomFault==0 ) oomFault();
g.nOomFault++;
if( !g.bOomOnce ) g.iOomCntdown = 1;
return 0;
}
}
return g.sOrigMem.xMalloc(nByte);
}
static void *oomRealloc(void *pOld, int nByte){
if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){
g.iOomCntdown--;
if( g.iOomCntdown==0 ){
if( g.nOomFault==0 ) oomFault();
g.nOomFault++;
if( !g.bOomOnce ) g.iOomCntdown = 1;
return 0;
}
}
return g.sOrigMem.xRealloc(pOld, nByte);
}
/*
** Print an error message and abort in such a way to indicate to the
** fuzzer that this counts as a crash.
@ -259,6 +299,7 @@ static void showHelp(void){
" --help Show this help text\n"
" --initdb DBFILE Initialize the in-memory database using template DBFILE\n"
" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
" --oom Run each test multiple times in a simulated OOM loop\n"
" --pagesize N Set the page size to N\n"
" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
" -q Reduced output\n"
@ -376,8 +417,13 @@ int main(int argc, char **argv){
sqlite3_stmt *pStmt = 0; /* Statement to insert testcase into dataDb */
const char *zDataOut = 0; /* Write compacted data to this output file */
int nHeader = 0; /* Bytes of header comment text on input file */
int oomFlag = 0; /* --oom */
int oomCnt = 0; /* Counter for the OOM loop */
char zErrBuf[200]; /* Space for the error message */
const char *zFailCode; /* Value of the TEST_FAILURE environment var */
zFailCode = getenv("TEST_FAILURE");
g.zArgv0 = argv[0];
for(i=1; i<argc; i++){
const char *z = argv[i];
@ -431,6 +477,9 @@ int main(int argc, char **argv){
abendError("unknown --mode: %s", z);
}
}else
if( strcmp(z,"oom")==0 ){
oomFlag = 1;
}else
if( strcmp(z,"pagesize")==0 ){
if( i>=argc-1 ) abendError("missing argument on %s", argv[i]);
pageSize = integerValue(argv[++i]);
@ -480,6 +529,13 @@ int main(int argc, char **argv){
rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
if( rc ) abendError("heap configuration failed: %d\n", rc);
}
if( oomFlag ){
sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g.sOrigMem);
g.sOomMem = g.sOrigMem;
g.sOomMem.xMalloc = oomMalloc;
g.sOomMem.xRealloc = oomRealloc;
sqlite3_config(SQLITE_CONFIG_MALLOC, &g.sOomMem);
}
if( nLook>0 ){
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
if( szLook>0 ){
@ -557,45 +613,15 @@ int main(int argc, char **argv){
zIn[iNext] = cSaved;
continue;
}
rc = sqlite3_open_v2(
"main.db", &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY,
0);
if( rc!=SQLITE_OK ){
abendError("Unable to open the in-memory database");
}
if( pLook ){
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook, nLook);
if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc);
}
if( zInitDb ){
sqlite3_backup *pBackup;
pBackup = sqlite3_backup_init(db, "main", dbInit, "main");
rc = sqlite3_backup_step(pBackup, -1);
if( rc!=SQLITE_DONE ){
abendError("attempt to initialize the in-memory database failed (rc=%d)",
rc);
}
sqlite3_backup_finish(pBackup);
}
#ifndef SQLITE_OMIT_TRACE
if( verboseFlag ) sqlite3_trace(db, traceCallback, 0);
#endif
sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000);
if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding);
if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize);
if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL");
zSql = &zIn[i];
if( verboseFlag ){
printf("INPUT (offset: %d, size: %d): [%s]\n",
i, (int)strlen(&zIn[i]), &zIn[i]);
}else if( multiTest && !quietFlag ){
int pct = 10*iNext/nIn;
int pct = oomFlag ? 100*iNext/nIn : ((10*iNext)/nIn)*10;
if( pct!=lastPct ){
if( lastPct<0 ) printf("fuzz test:");
printf(" %d%%", pct*10);
printf(" %d%%", pct);
fflush(stdout);
lastPct = pct;
}
@ -611,8 +637,84 @@ int main(int argc, char **argv){
zSql = zToFree = sqlite3_mprintf("SELECT strftime(%s);", zSql);
break;
}
zErrMsg = 0;
rc = sqlite3_exec(db, zSql, verboseFlag ? execCallback : execNoop, 0, &zErrMsg);
if( oomFlag ){
oomCnt = g.iOomCntdown = 1;
g.nOomFault = 0;
g.bOomOnce = 1;
if( verboseFlag ) printf("Once.%d\n", oomCnt);
}else{
oomCnt = 0;
}
do{
rc = sqlite3_open_v2(
"main.db", &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY,
0);
if( rc!=SQLITE_OK ){
abendError("Unable to open the in-memory database");
}
if( pLook ){
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook, nLook);
if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc);
}
if( zInitDb ){
sqlite3_backup *pBackup;
pBackup = sqlite3_backup_init(db, "main", dbInit, "main");
rc = sqlite3_backup_step(pBackup, -1);
if( rc!=SQLITE_DONE ){
abendError("attempt to initialize the in-memory database failed (rc=%d)",
rc);
}
sqlite3_backup_finish(pBackup);
}
#ifndef SQLITE_OMIT_TRACE
if( verboseFlag ) sqlite3_trace(db, traceCallback, 0);
#endif
sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000);
if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding);
if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize);
if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL");
g.bOomEnable = 1;
if( verboseFlag ){
zErrMsg = 0;
rc = sqlite3_exec(db, zSql, execCallback, 0, &zErrMsg);
if( zErrMsg ){
sqlite3_snprintf(sizeof(zErrBuf),zErrBuf,"%z", zErrMsg);
zErrMsg = 0;
}
}else {
rc = sqlite3_exec(db, zSql, execNoop, 0, 0);
}
g.bOomEnable = 0;
rc = sqlite3_close(db);
if( rc ){
abendError("sqlite3_close() failed with rc=%d", rc);
}
if( sqlite3_memory_used()>0 ){
abendError("memory in use after close: %lld bytes", sqlite3_memory_used());
}
if( oomFlag ){
if( g.nOomFault==0 || oomCnt>2000 ){
if( g.bOomOnce ){
oomCnt = g.iOomCntdown = 1;
g.bOomOnce = 0;
}else{
oomCnt = 0;
}
}else{
g.iOomCntdown = ++oomCnt;
g.nOomFault = 0;
}
if( oomCnt ){
if( verboseFlag ){
printf("%s.%d\n", g.bOomOnce ? "Once" : "Multi", oomCnt);
}
nTest++;
}
}
}while( oomCnt>0 );
if( zToFree ){
sqlite3_free(zToFree);
zToFree = 0;
@ -621,29 +723,18 @@ int main(int argc, char **argv){
if( verboseFlag ){
printf("RESULT-CODE: %d\n", rc);
if( zErrMsg ){
printf("ERROR-MSG: [%s]\n", zErrMsg);
printf("ERROR-MSG: [%s]\n", zErrBuf);
}
}
sqlite3_free(zErrMsg);
rc = sqlite3_close(db);
if( rc ){
abendError("sqlite3_close() failed with rc=%d", rc);
}
if( sqlite3_memory_used()>0 ){
abendError("memory in use after close: %lld bytes", sqlite3_memory_used());
}
if( nTest==1 ){
/* Simulate an error if the TEST_FAILURE environment variable is "5" */
char *zFailCode = getenv("TEST_FAILURE");
if( zFailCode ){
if( zFailCode[0]=='5' && zFailCode[1]==0 ){
abendError("simulated failure");
}else if( zFailCode[0]!=0 ){
/* If TEST_FAILURE is something other than 5, just exit the test
** early */
printf("\nExit early due to TEST_FAILURE being set");
break;
}
/* Simulate an error if the TEST_FAILURE environment variable is "5" */
if( zFailCode ){
if( zFailCode[0]=='5' && zFailCode[1]==0 ){
abendError("simulated failure");
}else if( zFailCode[0]!=0 ){
/* If TEST_FAILURE is something other than 5, just exit the test
** early */
printf("\nExit early due to TEST_FAILURE being set");
break;
}
}
}