mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Attempt to enhance fuzzcheck to do some simple invariant testing on queries.
This is an incremental check-in for a work-in-progress. FossilOrigin-Name: ce2d780163b3a28486904860a1815acc4169c09b971cfd199bb58d1e9a57b000
This commit is contained in:
124
test/fuzzcheck.c
124
test/fuzzcheck.c
@ -830,6 +830,13 @@ static int progress_handler(void *pClientData) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Flag bits set by block_troublesome_sql()
|
||||
*/
|
||||
#define BTS_SELECT 0x000001
|
||||
#define BTS_NONSELECT 0x000002
|
||||
#define BTS_BADFUNC 0x000004
|
||||
|
||||
/*
|
||||
** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and
|
||||
** "PRAGMA parser_trace" since they can dramatically increase the
|
||||
@ -838,63 +845,121 @@ static int progress_handler(void *pClientData) {
|
||||
** Also block ATTACH if attaching a file from the filesystem.
|
||||
*/
|
||||
static int block_troublesome_sql(
|
||||
void *Notused,
|
||||
void *pClientData,
|
||||
int eCode,
|
||||
const char *zArg1,
|
||||
const char *zArg2,
|
||||
const char *zArg3,
|
||||
const char *zArg4
|
||||
){
|
||||
(void)Notused;
|
||||
(void)zArg2;
|
||||
unsigned int *pFlags = (unsigned int*)pClientData;
|
||||
(void)zArg3;
|
||||
(void)zArg4;
|
||||
if( eCode==SQLITE_PRAGMA ){
|
||||
if( sqlite3_stricmp("busy_timeout",zArg1)==0
|
||||
&& (zArg2==0 || strtoll(zArg2,0,0)>100 || strtoll(zArg2,0,10)>100)
|
||||
){
|
||||
return SQLITE_DENY;
|
||||
}else if( eVerbosity==0 ){
|
||||
if( sqlite3_strnicmp("vdbe_", zArg1, 5)==0
|
||||
|| sqlite3_stricmp("parser_trace", zArg1)==0
|
||||
|| sqlite3_stricmp("temp_store_directory", zArg1)==0
|
||||
switch( eCode ){
|
||||
case SQLITE_PRAGMA: {
|
||||
if( sqlite3_stricmp("busy_timeout",zArg1)==0
|
||||
&& (zArg2==0 || strtoll(zArg2,0,0)>100 || strtoll(zArg2,0,10)>100)
|
||||
){
|
||||
return SQLITE_DENY;
|
||||
}else if( eVerbosity==0 ){
|
||||
if( sqlite3_strnicmp("vdbe_", zArg1, 5)==0
|
||||
|| sqlite3_stricmp("parser_trace", zArg1)==0
|
||||
|| sqlite3_stricmp("temp_store_directory", zArg1)==0
|
||||
){
|
||||
return SQLITE_DENY;
|
||||
}
|
||||
}else if( sqlite3_stricmp("oom",zArg1)==0
|
||||
&& zArg2!=0 && zArg2[0]!=0 ){
|
||||
oomCounter = atoi(zArg2);
|
||||
}
|
||||
}else if( sqlite3_stricmp("oom",zArg1)==0
|
||||
&& zArg2!=0 && zArg2[0]!=0 ){
|
||||
oomCounter = atoi(zArg2);
|
||||
*pFlags |= BTS_NONSELECT;
|
||||
break;
|
||||
}
|
||||
}else if( eCode==SQLITE_ATTACH ){
|
||||
/* Deny the ATTACH if it is attaching anything other than an in-memory
|
||||
** database. */
|
||||
if( zArg1==0 ) return SQLITE_DENY;
|
||||
if( strcmp(zArg1,":memory:")==0 ) return SQLITE_OK;
|
||||
if( sqlite3_strglob("file:*[?]vfs=memdb", zArg1)==0
|
||||
&& sqlite3_strglob("file:*[^/a-zA-Z0-9_.]*[?]vfs=memdb", zArg1)!=0
|
||||
){
|
||||
return SQLITE_OK;
|
||||
case SQLITE_ATTACH: {
|
||||
/* Deny the ATTACH if it is attaching anything other than an in-memory
|
||||
** database. */
|
||||
*pFlags |= BTS_NONSELECT;
|
||||
if( zArg1==0 ) return SQLITE_DENY;
|
||||
if( strcmp(zArg1,":memory:")==0 ) return SQLITE_OK;
|
||||
if( sqlite3_strglob("file:*[?]vfs=memdb", zArg1)==0
|
||||
&& sqlite3_strglob("file:*[^/a-zA-Z0-9_.]*[?]vfs=memdb", zArg1)!=0
|
||||
){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return SQLITE_DENY;
|
||||
}
|
||||
case SQLITE_SELECT: {
|
||||
*pFlags |= BTS_SELECT;
|
||||
break;
|
||||
}
|
||||
case SQLITE_FUNCTION: {
|
||||
static const char *azBadFuncs[] = {
|
||||
"random",
|
||||
"randomblob",
|
||||
"rtreedepth",
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(azBadFuncs)/sizeof(azBadFuncs[0]); i++){
|
||||
if( sqlite3_stricmp(azBadFuncs[i], zArg2)==0 ){
|
||||
*pFlags |= BTS_BADFUNC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_READ: {
|
||||
/* Benign */
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
*pFlags |= BTS_NONSELECT;
|
||||
}
|
||||
return SQLITE_DENY;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Implementation found in fuzzinvariant.c */
|
||||
int fuzz_invariant(
|
||||
sqlite3 *db, /* The database connection */
|
||||
sqlite3_stmt *pStmt, /* Test statement stopped on an SQLITE_ROW */
|
||||
int iCnt, /* Invariant sequence number, starting at 0 */
|
||||
int iRow, /* The row number for pStmt */
|
||||
int *pbCorrupt /* IN/OUT: Flag indicating a corrupt database file */
|
||||
);
|
||||
|
||||
/*
|
||||
** Run the SQL text
|
||||
*/
|
||||
static int runDbSql(sqlite3 *db, const char *zSql){
|
||||
static int runDbSql(sqlite3 *db, const char *zSql, unsigned int *pBtsFlags){
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
int bCorrupt = 0;
|
||||
while( isspace(zSql[0]&0x7f) ) zSql++;
|
||||
if( zSql[0]==0 ) return SQLITE_OK;
|
||||
if( eVerbosity>=4 ){
|
||||
printf("RUNNING-SQL: [%s]\n", zSql);
|
||||
fflush(stdout);
|
||||
}
|
||||
(*pBtsFlags) = 0;
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int nRow = 0;
|
||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
nRow++;
|
||||
if( (*pBtsFlags)==BTS_SELECT ){
|
||||
int iCnt = 0;
|
||||
for(iCnt=0; iCnt<99999; iCnt++){
|
||||
rc = fuzz_invariant(db, pStmt, iCnt, nRow, &bCorrupt);
|
||||
if( rc==SQLITE_DONE ) break;
|
||||
if( eVerbosity>0 ){
|
||||
if( rc==SQLITE_OK ){
|
||||
printf("invariant-check: ok\n");
|
||||
}else if( rc==SQLITE_CORRUPT ){
|
||||
printf("invariant-check: failed due to database corruption\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( eVerbosity>=5 ){
|
||||
int j;
|
||||
for(j=0; j<sqlite3_column_count(pStmt); j++){
|
||||
@ -971,6 +1036,7 @@ int runCombinedDbSqlInput(
|
||||
char *zSql = 0; /* SQL text to run */
|
||||
int nSql; /* Bytes of SQL text */
|
||||
FuzzCtx cx; /* Fuzzing context */
|
||||
unsigned int btsFlags = 0; /* Parsing flags */
|
||||
|
||||
if( nByte<10 ) return 0;
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
@ -1058,7 +1124,7 @@ int runCombinedDbSqlInput(
|
||||
|
||||
/* Block debug pragmas and ATTACH/DETACH. But wait until after
|
||||
** deserialize to do this because deserialize depends on ATTACH */
|
||||
sqlite3_set_authorizer(cx.db, block_troublesome_sql, 0);
|
||||
sqlite3_set_authorizer(cx.db, block_troublesome_sql, &btsFlags);
|
||||
|
||||
#ifdef VT02_SOURCES
|
||||
sqlite3_vt02_init(cx.db, 0, 0);
|
||||
@ -1083,7 +1149,7 @@ int runCombinedDbSqlInput(
|
||||
char cSaved = zSql[i+1];
|
||||
zSql[i+1] = 0;
|
||||
if( sqlite3_complete(zSql+j) ){
|
||||
rc = runDbSql(cx.db, zSql+j);
|
||||
rc = runDbSql(cx.db, zSql+j, &btsFlags);
|
||||
j = i+1;
|
||||
}
|
||||
zSql[i+1] = cSaved;
|
||||
@ -1093,7 +1159,7 @@ int runCombinedDbSqlInput(
|
||||
}
|
||||
}
|
||||
if( j<i ){
|
||||
runDbSql(cx.db, zSql+j);
|
||||
runDbSql(cx.db, zSql+j, &btsFlags);
|
||||
}
|
||||
}
|
||||
testrun_finished:
|
||||
|
Reference in New Issue
Block a user