]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the ability to process dbsqlfuzz cases in fuzzcheck and add an initial
authordrh <drh@noemail.net>
Fri, 25 Jan 2019 04:00:14 +0000 (04:00 +0000)
committerdrh <drh@noemail.net>
Fri, 25 Jan 2019 04:00:14 +0000 (04:00 +0000)
set of interesting dbsqlfuzz cases.

FossilOrigin-Name: fb9074ff450a67feaa62ca61d19154de26d5c8a8d147409ee6d1fbd667b2914f

Makefile.in
Makefile.msc
main.mk
manifest
manifest.uuid
test/fuzzcheck.c
test/fuzzdata8.db [new file with mode: 0644]

index 43fb38a46f2ef16e844d2d046476b9897f4c2b15..3904e45c0e589dbfd21b2b5af6eb91af1d1e6f91 100644 (file)
@@ -589,7 +589,8 @@ FUZZDATA = \
   $(TOP)/test/fuzzdata4.db \
   $(TOP)/test/fuzzdata5.db \
   $(TOP)/test/fuzzdata6.db \
-  $(TOP)/test/fuzzdata7.db
+  $(TOP)/test/fuzzdata7.db \
+  $(TOP)/test/fuzzdata8.db
 
 # Standard options to testfixture
 #
@@ -612,6 +613,12 @@ FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
 FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
+FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE
+FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
+#FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5
+FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
+FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
+FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
 FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
 DBFUZZ_OPT =
 
index fdd1f98f9c8da77094a3571fb80e591d88dfb59e..b4fa372f9a99eab8d30dae27a2aabd0a631a2cfd 100644 (file)
@@ -1626,7 +1626,8 @@ FUZZDATA = \
   $(TOP)\test\fuzzdata4.db \
   $(TOP)\test\fuzzdata5.db \
   $(TOP)\test\fuzzdata6.db \
-  $(TOP)\test\fuzzdata7.db
+  $(TOP)\test\fuzzdata7.db \
+  $(TOP)\test\fuzzdata8.db
 # <</mark>>
 
 # Additional compiler options for the shell.  These are only effective
@@ -1644,7 +1645,13 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1
 #
 MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5
 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1
-FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000
+FUZZCHECK_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DESERIALIZE
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
+
 FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.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
@@ -1731,10 +1738,10 @@ dbfuzz.exe:     $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H)
        $(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
 
 fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
-       $(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+       $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
 
 ossshell.exe:  $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H)
-       $(LTLINK) $(NO_WARN) $(FUZZCHECK_COMPILE_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+       $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
 
 sessionfuzz.exe:       zlib $(TOP)\test\sessionfuzz.c $(SQLITE3C) $(SQLITE3H)
        $(LTLINK) $(NO_WARN) -I$(ZLIBINCDIR) $(TOP)\test\sessionfuzz.c /link $(LDFLAGS) $(LTLINKOPTS) /LIBPATH:$(ZLIBLIBDIR) $(ZLIBLIB)
diff --git a/main.mk b/main.mk
index 9667db325350476c0f3a9cdb5e96186d20ceda55..d18863b11ea5a7b2c70e57d9c6b6340447bf529e 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -510,7 +510,8 @@ FUZZDATA = \
   $(TOP)/test/fuzzdata4.db \
   $(TOP)/test/fuzzdata5.db \
   $(TOP)/test/fuzzdata6.db \
-  $(TOP)/test/fuzzdata7.db
+  $(TOP)/test/fuzzdata7.db \
+  $(TOP)/test/fuzzdata8.db
 
 # Standard options to testfixture
 #
@@ -531,6 +532,11 @@ FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
 FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
+FUZZCHECK_OPT += -DSQLITE_ENABLE_DESERIALIZE
+FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
+FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
+FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
+FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
 DBFUZZ_OPT =
 KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
 ST_OPT = -DSQLITE_THREADSAFE=0
index eeded3f3c7547f71cd8ea8d7b8c46f97abc6a6dd..1a0ca0401f85c7d742f619eda1e84e2852c90eb6 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,10 +1,10 @@
-C Fix\sa\sbuffer\soverread\sin\sfts3\sthat\scould\soccur\sin\sa\sprefix\squery\son\sa\scorrupted\sdatabase.
-D 2019-01-24T17:41:12.741
+C Add\sthe\sability\sto\sprocess\sdbsqlfuzz\scases\sin\sfuzzcheck\sand\sadd\san\sinitial\nset\sof\sinteresting\sdbsqlfuzz\scases.
+D 2019-01-25T04:00:14.721
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
-F Makefile.in 0e7c107ebcaff26681bc5bcf017557db85aa828d6f7fd652d748b7a78072c298
+F Makefile.in 9947eae873c07ae894d4c8633b76c0a0daca7b9fd54401096a77d1a6c7b74359
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
-F Makefile.msc e04060b2138cefc198809d7adad70aebb4a667520b9133fe07a90a1769522dc7
+F Makefile.msc 5df60c70edb157feb2148a14c687551969599bd065875a0b959b6b139721ca72
 F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee
 F VERSION 453e2f4529ca208196d5567db28d549d7151f79efd33f6e6cfe6e613e583a0be
 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@ -436,7 +436,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 468c42acafaf69ae8d514d40cae78343b1d825aabd82e0368f6a3bcf8e4d2469
+F main.mk e28b19556f75ba6e841fc9c883d6a3c16edeae2d16d4edf32bf3c150725fc4d8
 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -984,7 +984,7 @@ F test/fuzz3.test 9c813e6613b837cb7a277b0383cd66bfa07042b4cf0317157c35852f30043c
 F test/fuzz4.test c229bcdb45518a89e1d208a21343e061503460ac69fae1539320a89f572eb634
 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
 F test/fuzz_malloc.test f348276e732e814802e39f042b1f6da6362a610af73a528d8f76898fde6b22f2
-F test/fuzzcheck.c 6edb2a0b6c8113cdac10f8e35b891be1a1b08ebacb1c2e2f93876d4d056e8e15
+F test/fuzzcheck.c 4082901a0665a5135b295fe81aa0ee325d42e1e28a0e3058a4082d249a321899
 F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
 F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
 F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
@@ -992,6 +992,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
 F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
 F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
 F test/fuzzdata7.db 3fc78e65dfe0be9df9e262075d5a335f18f627da47dfc691d1a7b822f34d4b99
+F test/fuzzdata8.db 8a96892bd2535578ff2ca27db823b7e149cfce6694c15ca80521fa758be605b1
 F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
 F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
@@ -1802,7 +1803,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 2d9cd06715092c312c8c0ec392696a0e90ed090b074e2082e0b830f1399aa941
-R aefdd33a1c83587ad3b0becf4339d1cc
-U dan
-Z df47a0dfd1efad16167473814c8098a6
+P d0d5689371577b2861d4a9464443d055f3256f3f51d89e0388233a4cbe2601ee
+R a483eb7b902b414248e92f9e64472126
+T *branch * dbsqlfuzz-in-fuzzcheck
+T *sym-dbsqlfuzz-in-fuzzcheck *
+T -sym-trunk *
+U drh
+Z 174f299274057b1d40bc6ac9348469f7
index c8a242b3f717d181390eb5d92c731450b848e799..71191813f9026b2b3380a72e9b7863a620236092 100644 (file)
@@ -1 +1 @@
-d0d5689371577b2861d4a9464443d055f3256f3f51d89e0388233a4cbe2601ee
\ No newline at end of file
+fb9074ff450a67feaa62ca61d19154de26d5c8a8d147409ee6d1fbd667b2914f
\ No newline at end of file
index 0db4167445058973dd45c9b4eb46a011bfa80d93..3175bf33e73d034071c9795e8ceb3ee28465d311 100644 (file)
@@ -69,6 +69,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <ctype.h>
+#include <assert.h>
 #include "sqlite3.h"
 #define ISSPACE(X) isspace((unsigned char)(X))
 #define ISDIGIT(X) isdigit((unsigned char)(X))
@@ -400,7 +401,6 @@ static void blobListFree(Blob *p){
   }
 }
 
-
 /* Return the current wall-clock time */
 static sqlite3_int64 timeOfDay(void){
   static sqlite3_vfs *clockVfs = 0;
@@ -419,6 +419,448 @@ static sqlite3_int64 timeOfDay(void){
   return t;
 }
 
+/***************************************************************************
+** Code to process combined database+SQL scripts generated by the
+** dbsqlfuzz fuzzer.
+*/
+
+/* An instance of the following object is passed by pointer as the
+** client data to various callbacks.
+*/
+typedef struct FuzzCtx {
+  sqlite3 *db;               /* The database connection */
+  sqlite3_int64 iCutoffTime; /* Stop processing at this time. */
+  sqlite3_int64 iLastCb;     /* Time recorded for previous progress callback */
+  sqlite3_int64 mxInterval;  /* Longest interval between two progress calls */
+  unsigned nCb;              /* Number of progress callbacks */
+  unsigned mxCb;             /* Maximum number of progress callbacks allowed */
+  unsigned execCnt;          /* Number of calls to the sqlite3_exec callback */
+  int timeoutHit;            /* True when reaching a timeout */
+} FuzzCtx;
+
+/* Verbosity level for the dbsqlfuzz test runner */
+static int eVerbosity = 0;
+
+/* True to activate PRAGMA vdbe_debug=on */
+static int bVdbeDebug = 0;
+
+/* Timeout for each fuzzing attempt, in milliseconds */
+static int iTimeout = 10000;   /* Defaults to 10 seconds */
+
+/* Maximum number of progress handler callbacks */
+static unsigned int mxProgressCb = 2000;
+
+/* Maximum string length in SQLite */
+static int lengthLimit = 1000000;
+
+/* Maximum byte-code program length in SQLite */
+static int vdbeOpLimit = 25000;
+
+/* Maximum size of the in-memory database */
+static sqlite3_int64 maxDbSize = 104857600;
+
+/*
+** Translate a single byte of Hex into an integer.
+** This routine only works if h really is a valid hexadecimal
+** character:  0..9a..fA..F
+*/
+static unsigned int hexToInt(unsigned int h){
+#ifdef SQLITE_EBCDIC
+  h += 9*(1&~(h>>4));   /* EBCDIC */
+#else
+  h += 9*(1&(h>>6));    /* ASCII */
+#endif
+  return h & 0xf;
+}
+
+/*
+** The first character of buffer zIn[0..nIn-1] is a '['.  This routine
+** checked to see if the buffer holds "[NNNN]" or "[+NNNN]" and if it
+** does it makes corresponding changes to the *pK value and *pI value
+** and returns true.  If the input buffer does not match the patterns,
+** no changes are made to either *pK or *pI and this routine returns false.
+*/
+static int isOffset(
+  const unsigned char *zIn,  /* Text input */
+  int nIn,                   /* Bytes of input */
+  unsigned int *pK,          /* half-byte cursor to adjust */
+  unsigned int *pI           /* Input index to adjust */
+){
+  int i;
+  unsigned int k = 0;
+  unsigned char c;
+  for(i=1; i<nIn && (c = zIn[i])!=']'; i++){
+    if( !isxdigit(c) ) return 0;
+    k = k*16 + hexToInt(c);
+  }
+  if( i==nIn ) return 0;
+  *pK = 2*k;
+  *pI += i;
+  return 1;
+}
+
+/*
+** Decode the text starting at zIn into a binary database file.
+** The maximum length of zIn is nIn bytes.  Compute the binary database
+** file contain in space obtained from sqlite3_malloc().
+**
+** Return the number of bytes of zIn consumed.  Or return -1 if there
+** is an error.  One potential error is that the recipe specifies a
+** database file larger than MX_FILE_SZ bytes.
+**
+** Abort on an OOM.
+*/
+static int decodeDatabase(
+  const unsigned char *zIn,      /* Input text to be decoded */
+  int nIn,                       /* Bytes of input text */
+  unsigned char **paDecode,      /* OUT: decoded database file */
+  int *pnDecode                  /* OUT: Size of decoded database */
+){
+  unsigned char *a;              /* Database under construction */
+  int mx = 0;                    /* Current size of the database */
+  sqlite3_uint64 nAlloc = 4096;  /* Space allocated in a[] */
+  unsigned int i;                /* Next byte of zIn[] to read */
+  unsigned int j;                /* Temporary integer */
+  unsigned int k;                /* half-byte cursor index for output */
+  unsigned int n;                /* Number of bytes of input */
+  unsigned char b = 0;
+  if( nIn<4 ) return -1;
+  n = (unsigned int)nIn;
+  a = sqlite3_malloc( nAlloc );
+  if( a==0 ){
+    fprintf(stderr, "Out of memory!\n");
+    exit(1);
+  }
+  memset(a, 0, nAlloc);
+  for(i=k=0; i<n; i++){
+    char c = zIn[i];
+    if( isxdigit(c) ){
+      k++;
+      if( k & 1 ){
+        b = hexToInt(c)*16;
+      }else{
+        b += hexToInt(c);
+        j = k/2 - 1;
+        if( j>=nAlloc ){
+          sqlite3_uint64 newSize;
+          if( nAlloc==MX_FILE_SZ || j>=MX_FILE_SZ ){
+            if( eVerbosity ){
+              fprintf(stderr, "Input database too big: max %d bytes\n",
+                      MX_FILE_SZ);
+            }
+            sqlite3_free(a);
+            return -1;
+          }
+          newSize = nAlloc*2;
+          if( newSize<=j ){
+            newSize = (j+4096)&~4095;
+          }
+          if( newSize>MX_FILE_SZ ){
+            if( j>=MX_FILE_SZ ){
+              sqlite3_free(a);
+              return -1;
+            }
+            newSize = MX_FILE_SZ;
+          }
+          a = sqlite3_realloc( a, newSize );
+          if( a==0 ){
+            fprintf(stderr, "Out of memory!\n");
+            exit(1);
+          }
+          assert( newSize > nAlloc );
+          memset(a+nAlloc, 0, newSize - nAlloc);
+          nAlloc = newSize;
+        }
+        if( j>=(unsigned)mx ){
+          mx = (j + 4095)&~4095;
+          if( mx>MX_FILE_SZ ) mx = MX_FILE_SZ;
+        }
+        assert( j<nAlloc );
+        a[j] = b;
+      }
+    }else if( zIn[i]=='[' && i<n-3 && isOffset(zIn+i, nIn-i, &k, &i) ){
+      continue;
+   }else if( zIn[i]=='\n' && i<n-4 && memcmp(zIn+i,"\n--\n",4)==0 ){
+      i += 4;
+      break;
+    }
+  }
+  *pnDecode = mx;
+  *paDecode = a;
+  return i;
+}
+
+/*
+** Progress handler callback.
+**
+** The argument is the cutoff-time after which all processing should
+** stop.  So return non-zero if the cut-off time is exceeded.
+*/
+static int progress_handler(void *pClientData) {
+  FuzzCtx *p = (FuzzCtx*)pClientData;
+  sqlite3_int64 iNow = timeOfDay();
+  int rc = iNow>=p->iCutoffTime;
+  sqlite3_int64 iDiff = iNow - p->iLastCb;
+  if( iDiff > p->mxInterval ) p->mxInterval = iDiff;
+  p->nCb++;
+  if( rc==0 && p->mxCb>0 && p->mxCb<=p->nCb ) rc = 1;
+  if( rc && !p->timeoutHit && eVerbosity ){
+    printf("Timeout on progress callback %d\n", p->nCb);
+    fflush(stdout);
+    p->timeoutHit = 1;
+  }
+  return rc;
+}
+
+/*
+** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and
+** "PRAGMA parser_trace" since they can dramatically increase the
+** amount of output without actually testing anything useful.
+**
+** Also block ATTACH and DETACH
+*/
+static int block_troublesome_sql(
+  void *Notused,
+  int eCode,
+  const char *zArg1,
+  const char *zArg2,
+  const char *zArg3,
+  const char *zArg4
+){
+  (void)Notused;
+  (void)zArg2;
+  (void)zArg3;
+  (void)zArg4;
+  if( eCode==SQLITE_PRAGMA ){
+    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( (eCode==SQLITE_ATTACH || eCode==SQLITE_DETACH)
+            && zArg1 && zArg1[0] ){
+    return SQLITE_DENY;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** Run the SQL text
+*/
+static int runDbSql(sqlite3 *db, const char *zSql){
+  int rc;
+  sqlite3_stmt *pStmt;
+  while( isspace(zSql[0]) ) zSql++;
+  if( zSql[0]==0 ) return SQLITE_OK;
+  if( eVerbosity>=3 ){
+    printf("RUNNING-SQL: [%s]\n", zSql);
+    fflush(stdout);
+  }
+  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+  if( rc==SQLITE_OK ){
+    while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
+      if( eVerbosity>=4 ){
+        int j;
+        for(j=0; j<sqlite3_column_count(pStmt); j++){
+          if( j ) printf(",");
+          switch( sqlite3_column_type(pStmt, j) ){
+            case SQLITE_NULL: {
+              printf("NULL");
+              break;
+            }
+            case SQLITE_INTEGER:
+            case SQLITE_FLOAT: {
+              printf("%s", sqlite3_column_text(pStmt, j));
+              break;
+            }
+            case SQLITE_BLOB: {
+              int n = sqlite3_column_bytes(pStmt, j);
+              int i;
+              const unsigned char *a;
+              a = (const unsigned char*)sqlite3_column_blob(pStmt, j);
+              printf("x'");
+              for(i=0; i<n; i++){
+                printf("%02x", a[i]);
+              }
+              printf("'");
+              break;
+            }
+            case SQLITE_TEXT: {
+              int n = sqlite3_column_bytes(pStmt, j);
+              int i;
+              const unsigned char *a;
+              a = (const unsigned char*)sqlite3_column_blob(pStmt, j);
+              printf("'");
+              for(i=0; i<n; i++){
+                if( a[i]=='\'' ){
+                  printf("''");
+                }else{
+                  putchar(a[i]);
+                }
+              }
+              printf("'");
+              break;
+            }
+          } /* End switch() */
+        } /* End for() */
+        printf("\n");
+        fflush(stdout);
+      } /* End if( eVerbosity>=4 ) */
+    } /* End while( SQLITE_ROW */
+    if( rc!=SQLITE_DONE && eVerbosity>=3 ){
+      printf("SQL-ERROR: (%d) %s\n", rc, sqlite3_errmsg(db));
+      fflush(stdout);
+    }
+  }else if( eVerbosity>=3 ){
+    printf("SQL-ERROR (%d): %s\n", rc, sqlite3_errmsg(db));
+    fflush(stdout);    
+  } /* End if( SQLITE_OK ) */
+  return sqlite3_finalize(pStmt);
+}
+
+/* Invoke this routine to run a single test case */
+int runCombinedDbSqlInput(const uint8_t *aData, size_t nByte){
+  int rc;                    /* SQLite API return value */
+  int iSql;                  /* Index in aData[] of start of SQL */
+  unsigned char *aDb = 0;    /* Decoded database content */
+  int nDb = 0;               /* Size of the decoded database */
+  int i;                     /* Loop counter */
+  int j;                     /* Start of current SQL statement */
+  char *zSql = 0;            /* SQL text to run */
+  int nSql;                  /* Bytes of SQL text */
+  FuzzCtx cx;                /* Fuzzing context */
+
+  if( nByte<10 ) return 0;
+  if( sqlite3_initialize() ) return 0;
+  if( sqlite3_memory_used()!=0 ){
+    int nAlloc = 0;
+    int nNotUsed = 0;
+    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0);
+    fprintf(stderr,"Memory leak in mutator: %lld bytes in %d allocations\n",
+            sqlite3_memory_used(), nAlloc);
+    exit(1);
+  }
+  memset(&cx, 0, sizeof(cx));
+  iSql = decodeDatabase((unsigned char*)aData, (int)nByte, &aDb, &nDb);
+  if( iSql<0 ) return 0;
+  nSql = nByte - iSql;
+  if( eVerbosity>=2 ){
+    printf(
+      "****** %d-byte input, %d-byte database, %d-byte script "
+      "******\n", (int)nByte, nDb, nSql);
+    fflush(stdout);
+  }
+  rc = sqlite3_open(0, &cx.db);
+  if( rc ) return 1;
+  if( bVdbeDebug ){
+    sqlite3_exec(cx.db, "PRAGMA vdbe_debug=ON", 0, 0, 0);
+  }
+
+  /* Invoke the progress handler frequently to check to see if we
+  ** are taking too long.  The progress handler will return true
+  ** (which will block further processing) if more than iTimeout seconds have
+  ** elapsed since the start of the test.
+  */
+  cx.iLastCb = timeOfDay();
+  cx.iCutoffTime = cx.iLastCb + iTimeout;  /* Now + iTimeout seconds */
+  cx.mxCb = mxProgressCb;
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+  sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx);
+#endif
+
+  /* Set a limit on the maximum size of a prepared statement, and the
+  ** maximum length of a string or blob */
+  if( vdbeOpLimit>0 ){
+    sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, vdbeOpLimit);
+  }
+  if( lengthLimit>0 ){
+    sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, lengthLimit);
+  }
+
+  if( nDb>=20 && aDb[18]==2 && aDb[19]==2 ){
+    aDb[18] = aDb[19] = 1;
+  }
+  rc = sqlite3_deserialize(cx.db, "main", aDb, nDb, nDb,
+          SQLITE_DESERIALIZE_RESIZEABLE |
+          SQLITE_DESERIALIZE_FREEONCLOSE);
+  if( rc ){
+    fprintf(stderr, "sqlite3_deserialize() failed with %d\n", rc);
+    goto testrun_finished;
+  }
+  if( maxDbSize>0 ){
+    sqlite3_int64 x = maxDbSize;
+    sqlite3_file_control(cx.db, "main", SQLITE_FCNTL_SIZE_LIMIT, &x);
+  }
+
+  /* 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);
+
+  /* Consistent PRNG seed */
+  sqlite3_randomness(0,0);
+
+  zSql = sqlite3_malloc( nSql + 1 );
+  if( zSql==0 ){
+    fprintf(stderr, "Out of memory!\n");
+  }else{
+    memcpy(zSql, aData+iSql, nSql);
+    zSql[nSql] = 0;
+    for(i=j=0; zSql[i]; i++){
+      if( zSql[i]==';' ){
+        char cSaved = zSql[i+1];
+        zSql[i+1] = 0;
+        if( sqlite3_complete(zSql+j) ){
+          rc = runDbSql(cx.db, zSql+j);
+          j = i+1;
+        }
+        zSql[i+1] = cSaved;
+        if( rc==SQLITE_INTERRUPT || progress_handler(&cx) ){
+          goto testrun_finished;
+        }
+      }
+    }
+    if( j<i ){
+      runDbSql(cx.db, zSql+j);
+    }
+  }
+testrun_finished:
+  sqlite3_free(zSql);
+  rc = sqlite3_close(cx.db);
+  if( rc!=SQLITE_OK ){
+    fprintf(stdout, "sqlite3_close() returns %d\n", rc);
+  }
+  if( eVerbosity ){
+    fprintf(stdout, "Peak memory usages: %f MB\n",
+       sqlite3_memory_highwater(1) / 1000000.0);
+  }
+  if( sqlite3_memory_used()!=0 ){
+    int nAlloc = 0;
+    int nNotUsed = 0;
+    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0);
+    fprintf(stderr,"Memory leak: %lld bytes in %d allocations\n",
+            sqlite3_memory_used(), nAlloc);
+    exit(1);
+  }
+  return 0;
+}
+
+/*
+** END of the dbsqlfuzz code
+***************************************************************************/
+
+/* Look at a SQL text and try to determine if it begins with a database
+** description, such as would be found in a dbsqlfuzz test case.  Return
+** true if this does appear to be a dbsqlfuzz test case and false otherwise.
+*/
+static int isDbSql(unsigned char *a, int n){
+  if( n>4 && memcmp(a,"\n--\n",4)==0 ) return 1;
+  while( n>0 && isspace(a[0]) ){ a++; n--; }
+  if( n>8 && memcmp(a,"53514c69",8)==0 ) return 1;
+  return 0;
+}
+
+
 /* Methods for the VHandle object
 */
 static int inmemClose(sqlite3_file *pFile){
@@ -951,6 +1393,7 @@ int main(int argc, char **argv){
       if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){
         quietFlag = 1;
         verboseFlag = 0;
+        eVerbosity = 0;
       }else
       if( strcmp(z,"rebuild")==0 ){
         rebuildFlag = 1;
@@ -976,8 +1419,18 @@ int main(int argc, char **argv){
       if( strcmp(z,"verbose")==0 || strcmp(z,"v")==0 ){
         quietFlag = 0;
         verboseFlag++;
+        eVerbosity++;
         if( verboseFlag>1 ) runFlags |= SQL_TRACE;
       }else
+      if( strcmp(z,"version")==0 ){
+        int ii;
+        const char *z;
+        printf("SQLite %s %s\n", sqlite3_libversion(), sqlite3_sourceid());
+        for(ii=0; (z = sqlite3_compileoption_get(ii))!=0; ii++){
+          printf("%s\n", z);
+        }
+        return 0;
+      }else
       {
         fatalError("unknown option: %s", argv[i]);
       }
@@ -1230,6 +1683,26 @@ int main(int argc, char **argv){
     */
     if( !verboseFlag && !quietFlag ) printf("%s:", zDbName);
     for(pSql=g.pFirstSql; pSql; pSql=pSql->pNext){
+      if( isDbSql(pSql->a, pSql->sz) ){
+        sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d",pSql->id);
+        if( verboseFlag ){
+          printf("%s\n", g.zTestName);
+          fflush(stdout);
+        }else if( !quietFlag ){
+          static int prevAmt = -1;
+          int idx = pSql->seq;
+          int amt = idx*10/(g.nSql);
+          if( amt!=prevAmt ){
+            printf(" %d%%", amt*10);
+            fflush(stdout);
+            prevAmt = amt;
+          }
+        }
+        runCombinedDbSqlInput(pSql->a, pSql->sz);
+        nTest++;
+        g.zTestName[0] = 0;
+        continue;
+      }
       for(pDb=g.pFirstDb; pDb; pDb=pDb->pNext){
         int openFlags;
         const char *zVfs = "inmem";
diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db
new file mode 100644 (file)
index 0000000..ba1723e
Binary files /dev/null and b/test/fuzzdata8.db differ