From f94c1902b95bf9f4b963972e9e5090a3d537607e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 7 Mar 2018 20:48:21 +0000 Subject: [PATCH] Add the sessionfuzz test program and data obtained from a week of running AFL. Automatically run this test program on any "make test" on unix. FossilOrigin-Name: ecaedfe596d4c05546bfd798fdca94aff6a81f55be7b17ddb65fc5547c4b5aa6 --- Makefile.in | 12 +- main.mk | 13 +- manifest | 18 +- manifest.uuid | 2 +- test/sessionfuzz-data1.db | Bin 0 -> 258048 bytes test/sessionfuzz.c | 1010 +++++++++++++++++++++++++++++++++++++ 6 files changed, 1040 insertions(+), 15 deletions(-) create mode 100644 test/sessionfuzz-data1.db create mode 100644 test/sessionfuzz.c diff --git a/Makefile.in b/Makefile.in index 862f397977..96ef34009e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -650,6 +650,9 @@ ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3. $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \ $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS) +sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h + $(CC) $(CFLAGS) -I. -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS) + dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS) @@ -1166,14 +1169,17 @@ fulltestonly: $(TESTPROGS) fuzztest ./testfixture$(TEXE) $(TOP)/test/full.test # Fuzz testing -fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) +fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(TEXE) $(FUZZDATA) + ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db -fastfuzztest: fuzzcheck$(TEXE) $(FUZZDATA) +fastfuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(TEXE) --limit-mem 100M $(FUZZDATA) + ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db -valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) +valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA) + valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db # The veryquick.test TCL tests. # diff --git a/main.mk b/main.mk index cdbef4e44e..e5722c5827 100644 --- a/main.mk +++ b/main.mk @@ -575,6 +575,9 @@ ossshell$(EXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h -DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) \ $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c $(TLIBS) $(THREADLIB) +sessionfuzz$(EXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h + $(TCC) -o sessionfuzz$(EXE) $(TOP)/test/sessionfuzz.c -lz $(TLIBS) $(THREADLIB) + mptester$(EXE): sqlite3.c $(TOP)/mptest/mptest.c $(TCCX) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \ $(TLIBS) $(THREADLIB) @@ -895,14 +898,17 @@ fulltestonly: $(TESTPROGS) fuzztest queryplantest: testfixture$(EXE) sqlite3$(EXE) ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner $(TESTOPTS) -fuzztest: fuzzcheck$(EXE) $(FUZZDATA) +fuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(EXE) $(FUZZDATA) + ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db -fastfuzztest: fuzzcheck$(EXE) $(FUZZDATA) +fastfuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(EXE) --limit-mem 100M $(FUZZDATA) + ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db -valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) +valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db valgrind ./fuzzcheck$(EXE) --cell-size-check --limit-mem 10M --timeout 600 $(FUZZDATA) + valgrind ./sessionfuzz run $(TOP)/test/sessionfuzz-data1.db # The veryquick.test TCL tests. # @@ -1066,6 +1072,7 @@ clean: rm -f mptester mptester.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe + rm -f sessionfuzz rm -f sqldiff sqldiff.exe rm -f fts5.* fts5parse.* rm -f lsm.h lsm1.c diff --git a/manifest b/manifest index c7b99317a7..340c35486e 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -C Update\sthe\sautoconf\sMakefile\sfor\sMSVC. -D 2018-03-07T15:54:39.405 +C Add\sthe\ssessionfuzz\stest\sprogram\sand\sdata\sobtained\sfrom\sa\sweek\sof\srunning\nAFL.\s\sAutomatically\srun\sthis\stest\sprogram\son\sany\s"make\stest"\son\sunix. +D 2018-03-07T20:48:21.666 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea -F Makefile.in 1d5a68043cc4d8a6e45b37e2639b148cdd7973aa75e90ec71e12d55cd95e32c0 +F Makefile.in 7016fc56c6b9bfe5daac4f34be8be38d8c0b5fab79ccbfb764d3b23bf1c6fff3 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 9d5201ef7e4f575d94ec6cd8a29a40ec3e4e150a01903afad385ccde72b30759 F README.md 1d5342ebda97420f114283e604e5fe99b0da939d63b76d492eabbaae23488276 @@ -411,7 +411,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 761e48fd24449071b8f8480449122fa59c052904666f72d803c64ae09b139298 +F main.mk 63668484c95454af7fc04a384da27ac556f27368d6d0c345e405e1677c66768f F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -1215,6 +1215,8 @@ F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3 F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840 F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be +F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb +F test/sessionfuzz.c 8167652afa13b6363825151c44ebcad9c993651e84537be94ec58e5004823f3d F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879 F test/shared3.test ab693f9b6e156b8bfb2a0ad94f29fe69602a5d38 @@ -1710,7 +1712,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d6fa938919dbb3fe73ccdd3cbf0e9264d524ed79125f93f977a7d91c425db821 -R 2a9575451278c1a4c315fccdfdca1672 -U mistachkin -Z e57bc875167796d343177373820c09eb +P 36fec7a4a75006d860aaf3ea6707cea25c5e16f2ac05c21c27fde80f3bfeec63 +R e9b5633f22c17863b715b8220bf589aa +U drh +Z 0dea7c28192df29380ebcdd90caa6963 diff --git a/manifest.uuid b/manifest.uuid index 00e217aaf3..2cbb84b4ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -36fec7a4a75006d860aaf3ea6707cea25c5e16f2ac05c21c27fde80f3bfeec63 \ No newline at end of file +ecaedfe596d4c05546bfd798fdca94aff6a81f55be7b17ddb65fc5547c4b5aa6 \ No newline at end of file diff --git a/test/sessionfuzz-data1.db b/test/sessionfuzz-data1.db new file mode 100644 index 0000000000000000000000000000000000000000..df10e10bcd7ad96b512dac036861c4e485aa5268 GIT binary patch literal 258048 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 +#include +#include +#include "zlib.h" + +/* +** Implementation of the "sqlar_uncompress(X,SZ)" SQL function +** +** Parameter SZ is interpreted as an integer. If it is less than or +** equal to zero, then this function returns a copy of X. Or, if +** SZ is equal to the size of X when interpreted as a blob, also +** return a copy of X. Otherwise, decompress blob X using zlib +** utility function uncompress() and return the results (another +** blob). +*/ +static void sqlarUncompressFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + uLong nData; + uLongf sz; + + assert( argc==2 ); + sz = sqlite3_value_int(argv[1]); + + if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){ + sqlite3_result_value(context, argv[0]); + }else{ + const Bytef *pData= sqlite3_value_blob(argv[0]); + Bytef *pOut = sqlite3_malloc(sz); + if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){ + sqlite3_result_error(context, "error in uncompress()", -1); + }else{ + sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT); + } + sqlite3_free(pOut); + } +} + + +/* Run a chunk of SQL. If any errors happen, print an error message +** and exit. +*/ +static void runSql(sqlite3 *db, const char *zSql){ + int rc; + char *zErr = 0; + rc = sqlite3_exec(db, zSql, 0, 0, &zErr); + if( rc || zErr ){ + fprintf(stderr, "SQL failed: rc=%d zErr=[%s]\n", rc, zErr); + fprintf(stderr, "SQL: [%s]\n", zSql); + exit(1); + } +} + +/* +** Write buffer to disk +*/ +static void writeFile(const char *zFilename, const void *pData, int nData){ + FILE *out; + int n; + out = fopen(zFilename, "wb"); + if( out==0 ){ + fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename); + exit(1); + } + n = (int)fwrite(pData, 1, nData, out); + fclose(out); + if( n!=nData ){ + fprintf(stderr, "only wrote %d of %d bytes to \"%s\"\n",n,nData,zFilename); + exit(1); + } +} + +/* +** Generate a changeset from session pSess and write it to zFile +*/ +static void makeChangeset(const char *zFile, sqlite3_session *pSess){ + void *pChg; + int nChg; + int rc; + rc = sqlite3session_changeset(pSess, &nChg, &pChg); + if( rc ){ + fprintf(stderr, "sqlite3session_changeset() returned %d\n", rc); + exit(1); + } + writeFile(zFile, pChg, nChg); + sqlite3_free(pChg); +} + +/* +** Read a file from disk. Space to hold the answer is obtained from +** sqlite3_malloc64(). +*/ +static void readFile(const char *zName, void **ppData, int *pnData){ + FILE *in = fopen(zName, "rb"); + long nIn; + size_t nRead; + char *pBuf; + *ppData = 0; + *pnData = 0; + if( in==0 ){ + fprintf(stderr, "Cannot open \"%s\" for reading\n", zName); + exit(1); + } + fseek(in, 0, SEEK_END); + nIn = ftell(in); + rewind(in); + pBuf = sqlite3_malloc64( nIn+1 ); + if( pBuf==0 ){ + fprintf(stderr, "Failed to malloc %lld bytes\n", (sqlite3_int64)(nIn+1)); + exit(1); + } + nRead = fread(pBuf, 1, nIn, in); + fclose(in); + if( nRead!=nIn ){ + fprintf(stderr, "Read only %d of %d bytes from %s\n", (int)nRead, (int)nIn, + zName); + exit(1); + } + pBuf[nIn] = 0; + *pnData = nIn; + *ppData = pBuf; +} + +/* +** The conflict callback +*/ +static int conflictCall( + void *NotUsed, + int eConflict, + sqlite3_changeset_iter *p +){ + (void)NotUsed; + (void)p; + printf("Conflict %d\n", eConflict); + return SQLITE_CHANGESET_OMIT; +} + +/* +** Reset the database file +*/ +static void db_reset(sqlite3 *db){ + unsigned char *pData; + int nData; + int rc; + + nData = sizeof(aDbBytes); + pData = sqlite3_malloc64( nData ); + if( pData==0 ){ + fprintf(stderr, "could not allocate %d bytes\n", nData); + exit(1); + } + memcpy(pData, aDbBytes, nData); + rc = sqlite3_deserialize(db, 0, pData, nData, nData, + SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE); + if( rc ){ + fprintf(stderr, "sqlite3_deserialize() failed with %d: %s\n", + rc, sqlite3_errmsg(db)); + exit(1); + } +} + +/* +** Given a full file pathname, return a pointer to the tail. +** Example: +** +** input: /home/drh/sqlite/abc.db +** output: abc.db +*/ +static const char *fileTail(const char *z){ + const char *zOut = z; + while( z[0] ){ + if( z[0]=='/' && z[1]!=0 ) zOut = &z[1]; + z++; + } + return zOut; +} + +int main(int argc, char **argv){ + const char *zCmd; + sqlite3 *db; + int rc; + sqlite3_session *pSess; + sqlite3_stmt *pStmt; + void *pChgset; + int nChgset; + int bVerbose = 0; + + if( argc<2 ){ + fprintf(stderr, "%s", zHelp); + exit(1); + } + rc = sqlite3_open_v2(":memory:",&db, + SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "memdb"); + if( rc ){ + fprintf(stderr, "Failed to open :memory: database: %s\n", + sqlite3_errmsg(db)); + exit(1); + } + db_reset(db); + zCmd = argv[1]; + if( strcmp(zCmd, "setup")==0 ){ + if( argc!=2 ){ + fprintf(stdout, "Wrong number of arguments.\n%s", zHelp); + exit(1); + } + runSql(db, zFillSql); + rc = sqlite3session_create(db, "main", &pSess); + if( rc ){ + fprintf(stderr, "sqlite3session_create() returns %d\n", rc); + exit(1); + } + rc = sqlite3session_attach(pSess, 0); + if( rc ){ + fprintf(stderr, "sqlite3session_attach(db,0) returns %d\n", rc); + exit(1); + } + runSql(db, "INSERT INTO t4(z) VALUES('');"); + makeChangeset("c1.txt", pSess); + runSql(db, + "UPDATE t1 SET b=c, c=b WHERE a IN (5,7);\n" + "DELETE FROM t2 WHERE rowid IN (8,2);\n" + "INSERT OR IGNORE INTO t4 SELECT b FROM t1 WHERE b IS TRUE LIMIT 2;"); + makeChangeset("c2.txt", pSess); + runSql(db, "UPDATE t3 SET x=y, y=NULL WHERE rowid IN (1,3);"); + makeChangeset("c3.txt", pSess); + sqlite3session_delete(pSess); + }else + if( strcmp(zCmd, "run")==0 ){ + int i; + if( argc<3 ){ + fprintf(stdout, "Wrong number of arguments.\n%s", zHelp); + exit(1); + } + for(i=2; i= 512 + && memcmp(pChgset, "SQLite format 3", 16)==0 + ){ + sqlite3 *db2; + sqlite3_stmt *pStmt; + int nCase = 0; + /* This file is an SQL Archive containing many changesets */ + if( !bVerbose ){ printf("%s: ", fileTail(argv[i])); fflush(stdout); } + sqlite3_open_v2(":memory:", &db2, + SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE, "memdb"); + sqlite3_deserialize(db2, 0, pChgset, nChgset, nChgset, + SQLITE_DESERIALIZE_READONLY | SQLITE_DESERIALIZE_FREEONCLOSE); + sqlite3_create_function(db2, "sqlar_uncompress", 2, SQLITE_UTF8, 0, + sqlarUncompressFunc, 0, 0); + rc = sqlite3_prepare_v2(db2, "SELECT name, sqlar_uncompress(data,sz)" + " FROM sqlar", -1, &pStmt, 0); + if( rc ){ + fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db2)); + exit(1); + } + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + if( bVerbose ){ + printf("%s/%s:", fileTail(argv[i]), sqlite3_column_text(pStmt,0)); + fflush(stdout); + } + runSql(db, "BEGIN"); + pChgset = (unsigned char*)sqlite3_column_blob(pStmt, 1); + nChgset = sqlite3_column_bytes(pStmt, 1); + rc = sqlite3changeset_apply(db, nChgset, pChgset, 0, conflictCall, 0); + if( bVerbose ){ + printf(" Ok. rc=%d\n", rc); + fflush(stdout); + } + runSql(db, "ROLLBACK"); + nCase++; + } + sqlite3_finalize(pStmt); + sqlite3_close(db2); + if( bVerbose ) printf("%s: ", fileTail(argv[i])); + printf(" %d cases, 0 crashes\n", nCase); + fflush(stdout); + }else{ + /* The named file is just an ordinary changeset */ + printf("%s:", fileTail(argv[i])); + fflush(stdout); + runSql(db, "BEGIN"); + rc = sqlite3changeset_apply(db, nChgset, pChgset, 0, conflictCall, 0); + printf(" %d\n", rc); + fflush(stdout); + runSql(db, "ROLLBACK"); + sqlite3_free(pChgset); + } + } + }else + { + fprintf(stderr, "%s", zHelp); + exit(1); + } + rc = sqlite3_prepare_v2(db, "PRAGMA integrity_check;", -1, &pStmt, 0); + if( rc ){ + fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); + exit(1); + } + if( sqlite3_step(pStmt)!=SQLITE_ROW + || strcmp((const char*)sqlite3_column_text(pStmt,0),"ok")!=0 + ){ + fprintf(stderr, "Integrity check failed!\n"); + do{ + fprintf(stderr, "%s\n", sqlite3_column_text(pStmt,0)); + }while( sqlite3_step(pStmt)==SQLITE_ROW ); + } + sqlite3_finalize(pStmt); + sqlite3_close(db); + if( sqlite3_memory_used()>0 ){ + fprintf(stderr, "memory leak of %lld bytes\n", + sqlite3_memory_used()); + exit(1); + } + return 0; +} -- 2.47.2