mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +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:
@ -630,7 +630,7 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
|||||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||||
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c $(TOP)/test/fuzzinvariants.c
|
||||||
DBFUZZ_OPT =
|
DBFUZZ_OPT =
|
||||||
|
|
||||||
# This is the default Makefile target. The objects listed here
|
# This is the default Makefile target. The objects listed here
|
||||||
|
@ -1705,7 +1705,7 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
|
|||||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
|
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
|
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||||
|
|
||||||
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
|
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c $(TOP)\test\fuzzinvariants.c
|
||||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||||
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
|
||||||
KV_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
KV_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||||
|
7
main.mk
7
main.mk
@ -546,6 +546,9 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
|||||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||||
|
FUZZSRC += $(TOP)/test/fuzzcheck.c
|
||||||
|
FUZZSRC += $(TOP)/test/ossfuzz.c
|
||||||
|
FUZZSRC += $(TOP)/test/fuzzinvariants.c
|
||||||
DBFUZZ_OPT =
|
DBFUZZ_OPT =
|
||||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||||
@ -604,10 +607,10 @@ dbfuzz2$(EXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
|||||||
$(TCCX) -I. -g -O0 -DSTANDALONE -o dbfuzz2$(EXE) \
|
$(TCCX) -I. -g -O0 -DSTANDALONE -o dbfuzz2$(EXE) \
|
||||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) $(THREADLIB)
|
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS) $(THREADLIB)
|
||||||
|
|
||||||
fuzzcheck$(EXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(TOP)/test/ossfuzz.c
|
fuzzcheck$(EXE): $(FUZZSRC) sqlite3.c sqlite3.h
|
||||||
$(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
$(TCCX) -o fuzzcheck$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||||
-DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) -DSQLITE_OSS_FUZZ \
|
-DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) -DSQLITE_OSS_FUZZ \
|
||||||
$(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS) $(THREADLIB)
|
$(FUZZSRC) sqlite3.c $(TLIBS) $(THREADLIB)
|
||||||
|
|
||||||
ossshell$(EXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
|
ossshell$(EXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
|
||||||
$(TCCX) -o ossshell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
$(TCCX) -o ossshell$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \
|
||||||
|
22
manifest
22
manifest
@ -1,11 +1,11 @@
|
|||||||
C Do\snot\sremove\sthe\sEP_CanBeNull\sflag\sfrom\sexpressions\sduring\sa\sLEFT\sJOIN\nstrength\sreduction\sif\sthe\squery\salso\scontains\sa\sRIGHT\sJOIN.\sFix\sfor\nthe\sproblem\sidentified\sby\n[forum/forumpost/b40696f50145d21c|forum\spost\sb40696f50145d21c].
|
C Attempt\sto\senhance\sfuzzcheck\sto\sdo\ssome\ssimple\sinvariant\stesting\son\squeries.\nThis\sis\san\sincremental\scheck-in\sfor\sa\swork-in-progress.
|
||||||
D 2022-06-13T12:42:24.645
|
D 2022-06-14T19:12:25.257
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
F Makefile.in e45046a016985c8fedfc5e7aad88ee396033a1e9b4e929fd6e1033e4c39dba95
|
F Makefile.in bccb0ed3f05fc41aee15da77c844c48b5da419cbb9af35b8a147536c9ad1c822
|
||||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||||
F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3
|
F Makefile.msc de7cb3e095ce2fdc33513ccd76ebdaeda1483d0ddab0410fe65cbdeadd4c0ee1
|
||||||
F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e
|
F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e
|
||||||
F VERSION fa8e7d2d1cc962f9e14c6d410387cf75860ee139462763fda887c1be4261f824
|
F VERSION fa8e7d2d1cc962f9e14c6d410387cf75860ee139462763fda887c1be4261f824
|
||||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||||
@ -491,7 +491,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
|
|||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||||
F main.mk 80ac3d2f82eb21c6fb4423f9c7f8e207abb51be6676845a00e246cfb22f9c77c
|
F main.mk a5412510e5ec952915a7fda34e02079bb4e6ff8f97903f2a3d9ad2dee3e18044
|
||||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||||
@ -1085,7 +1085,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
|
|||||||
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
|
||||||
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
F test/fuzz_common.tcl b7197de6ed1ee8250a4f82d67876f4561b42ee8cbbfc6160dcb66331bad3f830
|
||||||
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
|
||||||
F test/fuzzcheck.c e34696a5db46738118b2efd14fb71f8458ecf0f482df8bbae18fa1d64db9ab7b
|
F test/fuzzcheck.c 08d629c91b8307630273eb1e2e9a12bf0cf83fa2934e2b94681e11bf43819ef2
|
||||||
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
|
F test/fuzzdata1.db 3e86d9cf5aea68ddb8e27c02d7dfdaa226347426c7eb814918e4d95475bf8517
|
||||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||||
@ -1097,6 +1097,7 @@ F test/fuzzdata8.db ca9a97f401b06b0d5376139ec7e1f9e773e13345a9a2d9ccc0032cdbfede
|
|||||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||||
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
|
F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc
|
||||||
|
F test/fuzzinvariants.c 37b1f99fe4a6335983651b6b97a250dacf03b9ef81a189e2b52aeeace88ab1b1
|
||||||
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||||
F test/gencol1.test cc0dbb0ee116e5602e18ea7d47f2a0f76b26e09a823b7c36ef254370c2b0f3c1
|
F test/gencol1.test cc0dbb0ee116e5602e18ea7d47f2a0f76b26e09a823b7c36ef254370c2b0f3c1
|
||||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||||
@ -1976,8 +1977,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 342c501f532523347e6c339351e02043dd6ee9e11a291224b65ea72bd6c2ba40
|
P b1be2259e2e08ec22a88bc9a18b3ab4d83246ad4c635c05cdf80d3eff84df06a
|
||||||
R a249dd322f3d0191f7349eb16a9ed1fc
|
R d9a53a2b707897d91318ee68037f4638
|
||||||
|
T *branch * query-invariant-tests
|
||||||
|
T *sym-query-invariant-tests *
|
||||||
|
T -sym-trunk *
|
||||||
U drh
|
U drh
|
||||||
Z 7bab454819c3e667fed9b310a0634268
|
Z 709cfc900b1da90b6bf9416298b653df
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
b1be2259e2e08ec22a88bc9a18b3ab4d83246ad4c635c05cdf80d3eff84df06a
|
ce2d780163b3a28486904860a1815acc4169c09b971cfd199bb58d1e9a57b000
|
124
test/fuzzcheck.c
124
test/fuzzcheck.c
@ -830,6 +830,13 @@ static int progress_handler(void *pClientData) {
|
|||||||
return rc;
|
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
|
** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and
|
||||||
** "PRAGMA parser_trace" since they can dramatically increase the
|
** "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.
|
** Also block ATTACH if attaching a file from the filesystem.
|
||||||
*/
|
*/
|
||||||
static int block_troublesome_sql(
|
static int block_troublesome_sql(
|
||||||
void *Notused,
|
void *pClientData,
|
||||||
int eCode,
|
int eCode,
|
||||||
const char *zArg1,
|
const char *zArg1,
|
||||||
const char *zArg2,
|
const char *zArg2,
|
||||||
const char *zArg3,
|
const char *zArg3,
|
||||||
const char *zArg4
|
const char *zArg4
|
||||||
){
|
){
|
||||||
(void)Notused;
|
unsigned int *pFlags = (unsigned int*)pClientData;
|
||||||
(void)zArg2;
|
|
||||||
(void)zArg3;
|
(void)zArg3;
|
||||||
(void)zArg4;
|
(void)zArg4;
|
||||||
if( eCode==SQLITE_PRAGMA ){
|
switch( eCode ){
|
||||||
if( sqlite3_stricmp("busy_timeout",zArg1)==0
|
case SQLITE_PRAGMA: {
|
||||||
&& (zArg2==0 || strtoll(zArg2,0,0)>100 || strtoll(zArg2,0,10)>100)
|
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;
|
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
|
*pFlags |= BTS_NONSELECT;
|
||||||
&& zArg2!=0 && zArg2[0]!=0 ){
|
break;
|
||||||
oomCounter = atoi(zArg2);
|
|
||||||
}
|
}
|
||||||
}else if( eCode==SQLITE_ATTACH ){
|
case SQLITE_ATTACH: {
|
||||||
/* Deny the ATTACH if it is attaching anything other than an in-memory
|
/* Deny the ATTACH if it is attaching anything other than an in-memory
|
||||||
** database. */
|
** database. */
|
||||||
if( zArg1==0 ) return SQLITE_DENY;
|
*pFlags |= BTS_NONSELECT;
|
||||||
if( strcmp(zArg1,":memory:")==0 ) return SQLITE_OK;
|
if( zArg1==0 ) return SQLITE_DENY;
|
||||||
if( sqlite3_strglob("file:*[?]vfs=memdb", zArg1)==0
|
if( strcmp(zArg1,":memory:")==0 ) return SQLITE_OK;
|
||||||
&& sqlite3_strglob("file:*[^/a-zA-Z0-9_.]*[?]vfs=memdb", zArg1)!=0
|
if( sqlite3_strglob("file:*[?]vfs=memdb", zArg1)==0
|
||||||
){
|
&& sqlite3_strglob("file:*[^/a-zA-Z0-9_.]*[?]vfs=memdb", zArg1)!=0
|
||||||
return SQLITE_OK;
|
){
|
||||||
|
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;
|
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
|
** 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;
|
int rc;
|
||||||
sqlite3_stmt *pStmt;
|
sqlite3_stmt *pStmt;
|
||||||
|
int bCorrupt = 0;
|
||||||
while( isspace(zSql[0]&0x7f) ) zSql++;
|
while( isspace(zSql[0]&0x7f) ) zSql++;
|
||||||
if( zSql[0]==0 ) return SQLITE_OK;
|
if( zSql[0]==0 ) return SQLITE_OK;
|
||||||
if( eVerbosity>=4 ){
|
if( eVerbosity>=4 ){
|
||||||
printf("RUNNING-SQL: [%s]\n", zSql);
|
printf("RUNNING-SQL: [%s]\n", zSql);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
(*pBtsFlags) = 0;
|
||||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
|
int nRow = 0;
|
||||||
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
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 ){
|
if( eVerbosity>=5 ){
|
||||||
int j;
|
int j;
|
||||||
for(j=0; j<sqlite3_column_count(pStmt); j++){
|
for(j=0; j<sqlite3_column_count(pStmt); j++){
|
||||||
@ -971,6 +1036,7 @@ int runCombinedDbSqlInput(
|
|||||||
char *zSql = 0; /* SQL text to run */
|
char *zSql = 0; /* SQL text to run */
|
||||||
int nSql; /* Bytes of SQL text */
|
int nSql; /* Bytes of SQL text */
|
||||||
FuzzCtx cx; /* Fuzzing context */
|
FuzzCtx cx; /* Fuzzing context */
|
||||||
|
unsigned int btsFlags = 0; /* Parsing flags */
|
||||||
|
|
||||||
if( nByte<10 ) return 0;
|
if( nByte<10 ) return 0;
|
||||||
if( sqlite3_initialize() ) return 0;
|
if( sqlite3_initialize() ) return 0;
|
||||||
@ -1058,7 +1124,7 @@ int runCombinedDbSqlInput(
|
|||||||
|
|
||||||
/* Block debug pragmas and ATTACH/DETACH. But wait until after
|
/* Block debug pragmas and ATTACH/DETACH. But wait until after
|
||||||
** deserialize to do this because deserialize depends on ATTACH */
|
** 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
|
#ifdef VT02_SOURCES
|
||||||
sqlite3_vt02_init(cx.db, 0, 0);
|
sqlite3_vt02_init(cx.db, 0, 0);
|
||||||
@ -1083,7 +1149,7 @@ int runCombinedDbSqlInput(
|
|||||||
char cSaved = zSql[i+1];
|
char cSaved = zSql[i+1];
|
||||||
zSql[i+1] = 0;
|
zSql[i+1] = 0;
|
||||||
if( sqlite3_complete(zSql+j) ){
|
if( sqlite3_complete(zSql+j) ){
|
||||||
rc = runDbSql(cx.db, zSql+j);
|
rc = runDbSql(cx.db, zSql+j, &btsFlags);
|
||||||
j = i+1;
|
j = i+1;
|
||||||
}
|
}
|
||||||
zSql[i+1] = cSaved;
|
zSql[i+1] = cSaved;
|
||||||
@ -1093,7 +1159,7 @@ int runCombinedDbSqlInput(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( j<i ){
|
if( j<i ){
|
||||||
runDbSql(cx.db, zSql+j);
|
runDbSql(cx.db, zSql+j, &btsFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testrun_finished:
|
testrun_finished:
|
||||||
|
269
test/fuzzinvariants.c
Normal file
269
test/fuzzinvariants.c
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
** 2022-06-14
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** This library is used by fuzzcheck to test query invariants.
|
||||||
|
**
|
||||||
|
** An sqlite3_stmt is passed in that has just returned SQLITE_ROW. This
|
||||||
|
** routine does:
|
||||||
|
**
|
||||||
|
** * Record the output of the current row
|
||||||
|
** * Construct an alternative query that should return the same row
|
||||||
|
** * Run the alternative query and verify that it does in fact return
|
||||||
|
** the same row
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
#include "sqlite3.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/* Forward references */
|
||||||
|
static char *fuzz_invariant_sql(sqlite3_stmt*, int);
|
||||||
|
static int sameValue(sqlite3_value*,sqlite3_value*);
|
||||||
|
static void reportInvariantFailed(sqlite3_stmt*,sqlite3_stmt*,int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Do an invariant check on pStmt. iCnt determines which invariant check to
|
||||||
|
** perform. The first check is iCnt==0.
|
||||||
|
**
|
||||||
|
** *pbCorrupt is a flag that, if true, indicates that the database file
|
||||||
|
** is known to be corrupt. A value of non-zero means "yes, the database
|
||||||
|
** is corrupt". A zero value means "we do not know whether or not the
|
||||||
|
** database is corrupt". The value might be set prior to entry, or this
|
||||||
|
** routine might set the value.
|
||||||
|
**
|
||||||
|
** Return values:
|
||||||
|
**
|
||||||
|
** SQLITE_OK This check was successful.
|
||||||
|
**
|
||||||
|
** SQLITE_DONE iCnt is out of range.
|
||||||
|
**
|
||||||
|
** SQLITE_CORRUPT The invariant failed, but the underlying database
|
||||||
|
** file is indicating that it is corrupt, which might
|
||||||
|
** be the cause of the malfunction.
|
||||||
|
**
|
||||||
|
** SQLITE_INTERNAL The invariant failed, and the database file is not
|
||||||
|
** corrupt. (This never happens because this function
|
||||||
|
** will call abort() following an invariant failure.)
|
||||||
|
**
|
||||||
|
** (other) Some other kind of error occurred.
|
||||||
|
*/
|
||||||
|
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 */
|
||||||
|
){
|
||||||
|
char *zTest;
|
||||||
|
sqlite3_stmt *pTestStmt = 0;
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
int nCol;
|
||||||
|
|
||||||
|
if( *pbCorrupt ) return SQLITE_DONE;
|
||||||
|
zTest = fuzz_invariant_sql(pStmt, iCnt);
|
||||||
|
if( zTest==0 ) return SQLITE_DONE;
|
||||||
|
rc = sqlite3_prepare_v2(db, zTest, -1, &pTestStmt, 0);
|
||||||
|
sqlite3_free(zTest);
|
||||||
|
if( rc ){
|
||||||
|
sqlite3_finalize(pTestStmt);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
nCol = sqlite3_column_count(pStmt);
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
sqlite3_bind_value(pTestStmt, i+1, sqlite3_column_value(pStmt,i));
|
||||||
|
}
|
||||||
|
while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
if( !sameValue(sqlite3_column_value(pStmt,i),
|
||||||
|
sqlite3_column_value(pTestStmt,i)) ) break;
|
||||||
|
}
|
||||||
|
if( i>=nCol ) break;
|
||||||
|
}
|
||||||
|
if( rc!=SQLITE_ROW ){
|
||||||
|
/* No matching output row found */
|
||||||
|
sqlite3_stmt *pCk = 0;
|
||||||
|
rc = sqlite3_prepare_v2(db, "PRAGMA integrity_check", -1, &pCk, 0);
|
||||||
|
if( rc ){
|
||||||
|
sqlite3_finalize(pCk);
|
||||||
|
sqlite3_finalize(pTestStmt);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc = sqlite3_step(pCk);
|
||||||
|
if( rc!=SQLITE_ROW
|
||||||
|
|| sqlite3_column_text(pCk, 0)==0
|
||||||
|
|| strcmp((const char*)sqlite3_column_text(pCk,0),"ok")!=0
|
||||||
|
){
|
||||||
|
*pbCorrupt = 1;
|
||||||
|
sqlite3_finalize(pCk);
|
||||||
|
sqlite3_finalize(pTestStmt);
|
||||||
|
return SQLITE_CORRUPT;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(pCk);
|
||||||
|
reportInvariantFailed(pStmt, pTestStmt, iRow);
|
||||||
|
return SQLITE_INTERNAL;
|
||||||
|
}
|
||||||
|
sqlite3_finalize(pTestStmt);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate SQL used to test a statement invariant.
|
||||||
|
**
|
||||||
|
** Return 0 if the iCnt is out of range.
|
||||||
|
*/
|
||||||
|
static char *fuzz_invariant_sql(sqlite3_stmt *pStmt, int iCnt){
|
||||||
|
const char *zIn;
|
||||||
|
size_t nIn;
|
||||||
|
const char *zAnd = "WHERE";
|
||||||
|
int i;
|
||||||
|
sqlite3_str *pTest;
|
||||||
|
sqlite3_stmt *pBase = 0;
|
||||||
|
sqlite3 *db = sqlite3_db_handle(pStmt);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if( iCnt<0 || iCnt>0 ) return 0;
|
||||||
|
zIn = sqlite3_sql(pStmt);
|
||||||
|
if( zIn==0 ) return 0;
|
||||||
|
nIn = strlen(zIn);
|
||||||
|
while( nIn>0 && (isspace(zIn[nIn-1]) || zIn[nIn-1]==';') ) nIn--;
|
||||||
|
if( strchr(zIn, '?') ) return 0;
|
||||||
|
pTest = sqlite3_str_new(0);
|
||||||
|
sqlite3_str_appendf(pTest, "SELECT * FROM (%.*s)", (int)nIn, zIn);
|
||||||
|
rc = sqlite3_prepare_v2(db, sqlite3_str_value(pTest), -1, &pBase, 0);
|
||||||
|
if( rc ){
|
||||||
|
sqlite3_finalize(pBase);
|
||||||
|
pBase = pStmt;
|
||||||
|
}
|
||||||
|
for(i=0; i<sqlite3_column_count(pStmt); i++){
|
||||||
|
if( sqlite3_column_type(pStmt, i)==SQLITE_NULL ){
|
||||||
|
sqlite3_str_appendf(pTest, " %s \"%w\" ISNULL", zAnd,
|
||||||
|
sqlite3_column_name(pBase,i));
|
||||||
|
}else{
|
||||||
|
sqlite3_str_appendf(pTest, " %s \"%s\"=?%d", zAnd,
|
||||||
|
sqlite3_column_name(pBase, i), i+1);
|
||||||
|
}
|
||||||
|
zAnd = "AND";
|
||||||
|
}
|
||||||
|
if( pBase!=pStmt ) sqlite3_finalize(pBase);
|
||||||
|
return sqlite3_str_finish(pTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return true if and only if v1 and is the same as v2.
|
||||||
|
*/
|
||||||
|
static int sameValue(sqlite3_value *v1, sqlite3_value *v2){
|
||||||
|
int x = 1;
|
||||||
|
if( sqlite3_value_type(v1)!=sqlite3_value_type(v2) ) return 0;
|
||||||
|
switch( sqlite3_value_type(v1) ){
|
||||||
|
case SQLITE_INTEGER: {
|
||||||
|
x = sqlite3_value_int64(v1)==sqlite3_value_int64(v2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_FLOAT: {
|
||||||
|
x = sqlite3_value_double(v1)==sqlite3_value_double(v2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_TEXT: {
|
||||||
|
const char *z1 = (const char*)sqlite3_value_text(v1);
|
||||||
|
const char *z2 = (const char*)sqlite3_value_text(v2);
|
||||||
|
x = ((z1==0 && z2==0) || (z1!=0 && z2!=0 && strcmp(z1,z1)==0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_BLOB: {
|
||||||
|
int len1 = sqlite3_value_bytes(v1);
|
||||||
|
const unsigned char *b1 = sqlite3_value_blob(v1);
|
||||||
|
int len2 = sqlite3_value_bytes(v2);
|
||||||
|
const unsigned char *b2 = sqlite3_value_blob(v2);
|
||||||
|
if( len1!=len2 ){
|
||||||
|
x = 0;
|
||||||
|
}else if( len1==0 ){
|
||||||
|
x = 1;
|
||||||
|
}else{
|
||||||
|
x = (b1!=0 && b2!=0 && memcmp(b1,b2,len1)==0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Print a single row from the prepared statement
|
||||||
|
*/
|
||||||
|
static void printRow(sqlite3_stmt *pStmt, int iRow){
|
||||||
|
int i, nCol;
|
||||||
|
nCol = sqlite3_column_count(pStmt);
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
printf("row%d.col%d] = ", iRow, i);
|
||||||
|
switch( sqlite3_column_type(pStmt, i) ){
|
||||||
|
case SQLITE_NULL: {
|
||||||
|
printf("NULL\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_INTEGER: {
|
||||||
|
printf("(integer) %lld\n", sqlite3_column_int64(pStmt, i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_FLOAT: {
|
||||||
|
printf("(float) %f\n", sqlite3_column_double(pStmt, i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_TEXT: {
|
||||||
|
printf("(text) \"%s\"\n", sqlite3_column_text(pStmt, i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SQLITE_BLOB: {
|
||||||
|
int n = sqlite3_column_bytes(pStmt, i);
|
||||||
|
int j;
|
||||||
|
unsigned const char *data = sqlite3_column_blob(pStmt, i);
|
||||||
|
printf("(blob %d bytes) x'", n);
|
||||||
|
for(j=0; j<20 && j<n; j++){
|
||||||
|
printf("%02x", data[j]);
|
||||||
|
}
|
||||||
|
if( j<n ) printf("...");
|
||||||
|
printf("'\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Report a failure of the invariant: The current output row of pOrig
|
||||||
|
** does not appear in any row of the output from pTest.
|
||||||
|
*/
|
||||||
|
static void reportInvariantFailed(
|
||||||
|
sqlite3_stmt *pOrig, /* The original query */
|
||||||
|
sqlite3_stmt *pTest, /* The alternative test query with a missing row */
|
||||||
|
int iRow /* Row number in pOrig */
|
||||||
|
){
|
||||||
|
int iTestRow = 0;
|
||||||
|
printf("Invariant check failed on row %d.\n", iRow);
|
||||||
|
printf("Original query --------------------------------------------------\n");
|
||||||
|
printf("%s\n", sqlite3_expanded_sql(pOrig));
|
||||||
|
printf("Alternative query -----------------------------------------------\n");
|
||||||
|
printf("%s\n", sqlite3_expanded_sql(pTest));
|
||||||
|
printf("Result row that is missing from the alternative -----------------\n");
|
||||||
|
printRow(pOrig, iRow);
|
||||||
|
printf("Complete results from the alternative query ---------------------\n");
|
||||||
|
sqlite3_reset(pTest);
|
||||||
|
while( sqlite3_step(pTest)==SQLITE_ROW ){
|
||||||
|
iTestRow++;
|
||||||
|
printRow(pTest, iTestRow);
|
||||||
|
}
|
||||||
|
sqlite3_finalize(pTest);
|
||||||
|
abort();
|
||||||
|
}
|
Reference in New Issue
Block a user