]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Update the changesetfuzz program to fuzz changeset schemas as well as data.
authordan <dan@noemail.net>
Tue, 6 Nov 2018 20:08:03 +0000 (20:08 +0000)
committerdan <dan@noemail.net>
Tue, 6 Nov 2018 20:08:03 +0000 (20:08 +0000)
FossilOrigin-Name: 141a93c843d501d8bb640228645ead0a83870c1c11e9d4b07ed24b296c69a0b8

ext/session/changesetfuzz.c
manifest
manifest.uuid

index c430ab4d6de8ad6cae98525b2d935e3b9fce952b..4ea61e1c129363fe8ccaf1ebd6fc617a53d9973b 100644 (file)
 **      (as both the old.* and new.* records of the new UPDATE change). If an
 **      UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
 **      and any "undefined" fields replaced with pseudo-randomly generated
-**      values. 
+**      values.
 **
 **   7. An UPDATE change that modifies N table columns may be modified so
 **      that it updates N-1 columns, so long as (N>1).
 **
+**   8. The "indirect" flag may be toggled for any change.
+**
+** Entire group of changes may also be operated on:
+**
+**   9. Duplicate an existing group.
+**
+**  10. Remove an existing group.
+**
+**  11. The positions of two groups may be exchanged.
+**
+** There are also schema changes:
+**
+**  12. A non-PK column may be added to a table. In this case a NULL 
+**      value is appended to all records.
+**
+**  13. A PK column may be added to a table. In this case a non-NULL 
+**      value is appended to all INSERT, DELETE and UPDATE old.* records.
+**      An "undefined" is appended to new.* UPDATE records.
+**
+**  14. A column may be removed from a table.  In this case the corresponding
+**      field is removed from all records. In cases where this leaves an UPDATE
+**      with no non-PK, non-undefined fields, the entire change is removed. If
+**      the table has more than on PK column, the column removed may be part of
+**      the PK. 
 */
 
 #include "sqlite3.h"
 #include <assert.h>
 #include <ctype.h>
 
-#define FUZZ_VALUE_SUB     1      /* Replace one value with a copy of another */
-#define FUZZ_VALUE_MOD     2      /* Modify content by 1 bit */
-#define FUZZ_VALUE_RND     3      /* Replace with pseudo-random value */
+#define FUZZ_VALUE_SUB       1    /* Replace one value with a copy of another */
+#define FUZZ_VALUE_MOD       2    /* Modify content by 1 bit */
+#define FUZZ_VALUE_RND       3    /* Replace with pseudo-random value */
+
+#define FUZZ_CHANGE_DUP      4    /* Duplicate an existing change */
+#define FUZZ_CHANGE_DEL      5    /* Completely remove one change */
+#define FUZZ_CHANGE_TYPE     6    /* Change the type of one change */
+#define FUZZ_CHANGE_FIELD    7    /* Change an UPDATE to modify fewer columns */
+#define FUZZ_CHANGE_INDIRECT 8    /* Toggle the "indirect" flag of a change */
+
+#define FUZZ_GROUP_DUP       9    /* Duplicate a change group */
+#define FUZZ_GROUP_DEL      10    /* Delete an entire change group */
+#define FUZZ_GROUP_SWAP     11    /* Exchange the position of two groups */
 
-#define FUZZ_CHANGE_DUP    4
-#define FUZZ_CHANGE_DEL    5
-#define FUZZ_CHANGE_TYPE   6
-#define FUZZ_CHANGE_FIELD  7
+#define FUZZ_COLUMN_ADD     12     /* Add column to table definition */
+#define FUZZ_COLUMN_ADDPK   13     /* Add PK column to table definition */
+#define FUZZ_COLUMN_DEL     14     /* Remove column from table definition */
 
 #if 0
 #define FUZZ_COLUMN_ADD    1      /* Add column to table definition */
-#define FUZZ_COLUMN_DEL    2      /* Remove column from table definition */
 #define FUZZ_PK_ADD        3      /* Add a PK column */
 #define FUZZ_PK_DEL        4      /* Delete a PK column */
 #define FUZZ_NAME_CHANGE   5      /* Change a table name */
@@ -274,8 +306,8 @@ typedef struct FuzzChange FuzzChange;
 struct FuzzChangeset {
   FuzzChangesetGroup **apGroup;   /* Array of groups in changeset */
   int nGroup;                     /* Number of items in list pGroup */
-  u8 *aVal[FUZZER_AVAL_SZ];       /* Array of first few values in changeset */
-  int nVal;                       /* Number of used slots in aVal[] */
+  u8 **apVal;                     /* Array of all values in changeset */
+  int nVal;                       /* Number of used slots in apVal[] */
   int nChange;                    /* Number of changes in changeset */
   int nUpdate;                    /* Number of UPDATE changes in changeset */
 };
@@ -287,7 +319,6 @@ struct FuzzChangesetGroup {
   u8 *aChange;                    /* Buffer containing array of changes */
   int szChange;                   /* Size of buffer aChange[] in bytes */
   int nChange;                    /* Number of changes in buffer aChange[] */
-  FuzzChangesetGroup *pNextGroup;
 };
 
 /*
@@ -295,11 +326,12 @@ struct FuzzChangesetGroup {
 */
 struct FuzzChange {
   int eType;                      /* One of the FUZZ_* constants above */
-  int iChange;                    /* Change to modify */
+  int iChange;                    /* Change or UPDATE to modify */
+  int iGroup;                     /* Group to modify */
+  int iDelete;                    /* Field to remove (FUZZ_COLUMN_DEL) */
   u8 *pSub1;
   u8 *pSub2;
   u8 aSub[128];                   /* Substitute value */
-
   int iCurrent;                   /* Current change number */
 };
 
@@ -444,9 +476,13 @@ static int fuzzParseRecord(u8 **ppRec, u8 *pEnd, FuzzChangeset *pParse){
 
   for(i=0; rc==SQLITE_OK && i<nCol && p<pEnd; i++){
     int sz;
-    if( pParse->nVal<FUZZER_AVAL_SZ ){
-      pParse->aVal[pParse->nVal++] = p;
+    if( (pParse->nVal & (pParse->nVal-1))==0 ){
+      int nNew = pParse->nVal ? pParse->nVal*2 : 4;
+      u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*));
+      if( apNew==0 ) return SQLITE_NOMEM;
+      pParse->apVal = apNew;
     }
+    pParse->apVal[pParse->nVal++] = p;
     rc = fuzzChangeSize(p, &sz);
     p += sz;
   }
@@ -627,7 +663,7 @@ static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
   int iSub;
 
   memset(pChange, 0, sizeof(FuzzChange));
-  pChange->eType = fuzzRandomInt(7) + FUZZ_VALUE_SUB;
+  pChange->eType = fuzzRandomInt(14) + FUZZ_VALUE_SUB;
 
   assert( pChange->eType==FUZZ_VALUE_SUB
        || pChange->eType==FUZZ_VALUE_MOD
@@ -636,23 +672,54 @@ static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
        || pChange->eType==FUZZ_CHANGE_DEL
        || pChange->eType==FUZZ_CHANGE_TYPE
        || pChange->eType==FUZZ_CHANGE_FIELD
+       || pChange->eType==FUZZ_CHANGE_INDIRECT
+       || pChange->eType==FUZZ_GROUP_DUP
+       || pChange->eType==FUZZ_GROUP_DEL
+       || pChange->eType==FUZZ_GROUP_SWAP
+       || pChange->eType==FUZZ_COLUMN_ADD
+       || pChange->eType==FUZZ_COLUMN_ADDPK
+       || pChange->eType==FUZZ_COLUMN_DEL
   );
 
+  pChange->iGroup = fuzzRandomInt(pParse->nGroup);
   pChange->iChange = fuzzRandomInt(pParse->nChange);
   if( pChange->eType==FUZZ_CHANGE_FIELD ){
     if( pParse->nUpdate==0 ) return -1;
     pChange->iChange = fuzzRandomInt(pParse->nUpdate);
   }
 
+  pChange->iDelete = -1;
+  if( pChange->eType==FUZZ_COLUMN_DEL ){
+    FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup];
+    int i;
+    pChange->iDelete = fuzzRandomInt(pGrp->nCol);
+    for(i=pGrp->nCol-1; i>=0; i--){
+      if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
+    }
+    if( i<0 ) return -1;
+  }
+
+  if( pChange->eType==FUZZ_GROUP_SWAP ){
+    FuzzChangesetGroup *pGrp;
+    int iGrp = pChange->iGroup;
+    if( pParse->nGroup==1 ) return -1;
+    while( iGrp==pChange->iGroup ){
+      iGrp = fuzzRandomInt(pParse->nGroup);
+    }
+    pGrp = pParse->apGroup[pChange->iGroup];
+    pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp];
+    pParse->apGroup[iGrp] = pGrp;
+  }
+
   if( pChange->eType==FUZZ_VALUE_SUB 
    || pChange->eType==FUZZ_VALUE_MOD 
    || pChange->eType==FUZZ_VALUE_RND 
   ){
     iSub = fuzzRandomInt(pParse->nVal);
-    pChange->pSub1 = pParse->aVal[iSub];
+    pChange->pSub1 = pParse->apVal[iSub];
     if( pChange->eType==FUZZ_VALUE_SUB ){
       iSub = fuzzRandomInt(pParse->nVal);
-      pChange->pSub2 = pParse->aVal[iSub];
+      pChange->pSub2 = pParse->apVal[iSub];
     }else{
       pChange->pSub2 = pChange->aSub;
     }
@@ -724,16 +791,18 @@ static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
 
 static int fuzzCopyChange(
   FuzzChangeset *pParse,
-  FuzzChangesetGroup *pGrp, 
+  int iGrp,
   FuzzChange *pFuzz,
   u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
 ){
+  FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
   u8 *p = *pp;
   u8 *pOut = *ppOut;
   u8 eType = p++[0];
   int iRec;
   int nRec = (eType==SQLITE_UPDATE ? 2 : 1);
   int iUndef = -1;
+  int nUpdate = 0;
 
   u8 eNew = eType;
   if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
@@ -774,9 +843,16 @@ static int fuzzCopyChange(
     }
   }
 
-  /* Copy the change type and indirect flag */
+  /* Copy the change type and indirect flag. If the fuzz mode is
+  ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for
+  ** fuzzing, invert the indirect flag.  */
   *(pOut++) = eNew;
-  *(pOut++) = *(p++);
+  if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
+    *(pOut++) = !(*(p++));
+  }else{
+    *(pOut++) = *(p++);
+  }
+
   for(iRec=0; iRec<nRec; iRec++){
     int i;
     for(i=0; i<pGrp->nCol; i++){
@@ -793,7 +869,7 @@ static int fuzzCopyChange(
 
       if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
         while( pCopy[0]==0x00 ){
-          pCopy = pParse->aVal[fuzzRandomInt(pParse->nVal)];
+          pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
         }
       }else if( p[0]==0x00 && pCopy[0]!=0x00 ){
         return -1;
@@ -801,15 +877,37 @@ static int fuzzCopyChange(
         if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
       }
 
-      if( eNew==eType || eType!=SQLITE_UPDATE || iRec==0 ){
-        fuzzChangeSize(pCopy, &sz);
-        memcpy(pOut, pCopy, sz);
-        pOut += sz;
+      if( pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete ){
+        if( eNew==eType || eType!=SQLITE_UPDATE || iRec==0 ){
+          fuzzChangeSize(pCopy, &sz);
+          memcpy(pOut, pCopy, sz);
+          pOut += sz;
+          nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
+        }
       }
 
       fuzzChangeSize(p, &sz);
       p += sz;
     }
+
+    if( iGrp==pFuzz->iGroup ){
+      if( pFuzz->eType==FUZZ_COLUMN_ADD ){
+        *(pOut++) = 0x05;
+      }else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
+        if( iRec==1 ){
+          *(pOut++) = 0x00;
+        }else{
+          u8 *pNew;
+          int szNew;
+          do {
+            pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
+          }while( pNew[0]==0x00 || pNew[0]==0x05 );
+          fuzzChangeSize(pNew, &szNew);
+          memcpy(pOut, pNew, szNew);
+          pOut += szNew;
+        }
+      }
+    }
   }
 
   if( pFuzz->iCurrent==pFuzz->iChange ){
@@ -818,8 +916,8 @@ static int fuzzCopyChange(
       memcpy(pOut, *ppOut, nByte);
       pOut += nByte;
     }
+
     if( pFuzz->eType==FUZZ_CHANGE_DEL ){
-      if( pGrp->nChange==1 ) return -1;
       pOut = *ppOut;
     }
     if( eNew!=eType && eNew==SQLITE_UPDATE ){
@@ -838,6 +936,15 @@ static int fuzzCopyChange(
     }
   }
 
+  /* If a column is being deleted from this group, and this change was an 
+  ** UPDATE, and there are now no non-PK, non-undefined columns in the 
+  ** change, remove it altogether. */
+  if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp 
+   && eType==SQLITE_UPDATE && nUpdate==0 
+  ){
+    pOut = *ppOut;
+  }
+
   *pp = p;
   *ppOut = pOut;
   pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
@@ -859,21 +966,73 @@ static int fuzzDoOneFuzz(
     for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
       FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
       int nTab = strlen(pGrp->zTab) + 1;
-      u8 *p;
-      int i;
+      int j;
+      int nRep = 1;
+
+      /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to
+      ** the next group. Unless this is the only group in the changeset - in
+      ** that case this change cannot be applied.
+      **
+      ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two
+      ** copies of the group. */
+      if( change.iGroup==iGrp ){
+        if( change.eType==FUZZ_GROUP_DEL ){
+          if( pParse->nGroup==1 ) rc = -1;
+          continue;
+        }
+        else if( change.eType==FUZZ_GROUP_DUP ){
+          nRep = 2;
+        }
+      }
 
-      /* Output a table header */
-      pOut++[0] = 'T';
-      pOut += fuzzPutVarint(pOut, pGrp->nCol);
-      memcpy(pOut, pGrp->aPK, pGrp->nCol);
-      pOut += pGrp->nCol;
-      memcpy(pOut, pGrp->zTab, nTab);
-      pOut += nTab;
-
-      /* Output the change array */
-      p = pGrp->aChange;
-      for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
-        rc = fuzzCopyChange(pParse, pGrp, &change, &p, &pOut);
+      for(j=0; j<nRep; j++){
+        int i;
+        u8 *pSaved;
+        u8 *p = pGrp->aChange;
+        int nCol = pGrp->nCol;
+        int iPKDel = 0;
+        if( iGrp==change.iGroup ){
+          if( change.eType==FUZZ_COLUMN_ADD 
+           || change.eType==FUZZ_COLUMN_ADDPK 
+          ){
+            nCol++;
+          }else if( change.eType==FUZZ_COLUMN_DEL ){
+            nCol--;
+            iPKDel = pGrp->aPK[change.iDelete];
+          }
+        }
+
+        /* Output a table header */
+        pOut++[0] = 'T';
+        pOut += fuzzPutVarint(pOut, nCol);
+
+        for(i=0; i<pGrp->nCol; i++){
+          if( iGrp!=change.iGroup || i!=change.iDelete ){
+            u8 v = pGrp->aPK[i];
+            if( iPKDel && v>iPKDel ) v--;
+            *(pOut++) = v;
+          }
+        }
+        if( nCol>pGrp->nCol ){
+          if( change.eType==FUZZ_COLUMN_ADD ){
+            *(pOut++) = 0x00;
+          }else{
+            u8 max = 0;
+            for(i=0; i<pGrp->nCol; i++){
+              if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
+            }
+            *(pOut++) = max+1;
+          }
+        }
+        memcpy(pOut, pGrp->zTab, nTab);
+        pOut += nTab;
+
+        /* Output the change array. */
+        pSaved = pOut;
+        for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
+          rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut);
+        }
+        if( pOut==pSaved ) rc = -1;
       }
     }
     if( rc==SQLITE_OK ){
@@ -916,7 +1075,7 @@ int main(int argc, char **argv){
         fuzzRandomSeed((unsigned int)iSeed);
         for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
           char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
-          fuzzDoOneFuzz(zOut, pBuf, &changeset);
+          rc = fuzzDoOneFuzz(zOut, pBuf, &changeset);
           sqlite3_free(zOut);
         }
         fuzzFree(pBuf);
@@ -927,6 +1086,7 @@ int main(int argc, char **argv){
   if( rc!=SQLITE_OK ){
     fprintf(stderr, "error while processing changeset: %d\n", rc);
   }
+
   return rc;
 }
 
index f7a39c9f657b57c5967ccb01b66be94c77e5300e..cffb5a40eefc59780981e2e3a0505566dd0ff877 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\spreliminary\sversion\sof\s"changesetfuzz"\sprogram.\sFor\sfuzzing\schangeset\sdata\nwithout\screating\scorrupt\schangesets.
-D 2018-11-05T20:37:33.019
+C Update\sthe\schangesetfuzz\sprogram\sto\sfuzz\schangeset\sschemas\sas\swell\sas\sdata.
+D 2018-11-06T20:08:03.912
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in d298b31769d4c737887102462cd45684786b09f2a626a80b3e413790fb436219
@@ -391,7 +391,7 @@ F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F ext/rtree/visual01.txt e9c2564083bcd30ec51b07f881bffbf0e12b50a3f6fced0c222c5c1d2f94ac66
 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a
-F ext/session/changesetfuzz.c 1e56326c4b76a6f1802ca73629409ce1eb10d60a388a43d8e7c74b33b1f4725c
+F ext/session/changesetfuzz.c 27aec2e060043eb7377d7075e20959c85c57a41f4f72c30f8bace12cc9b9af69
 F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e
 F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
 F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
@@ -1777,10 +1777,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 11d98414eac467affb0b3cf0c7e5cc3d43184fc2b6e7e898bb5277b51ea9e1fa
-R 147d5d75296309ad726c7c64dc2b1650
-T *branch * changesetfuzz
-T *sym-changesetfuzz *
-T -sym-trunk *
+P 81ac8745faac0bda8d68ac113f1938f0e25208642e8ceb2af452680086454cb5
+R 2ce6a540d3c541564d5607a6269445d4
 U dan
-Z e5d17ad373a9d021c09070dfd9d8422e
+Z 7a3bd8208ab7b3ca6eb82773978332aa
index d808b7ec90590e5f605fceb96bcfc8344b90d45b..7cd5b0a6c0b1bf2e9de59ff955d62a60799ed7e2 100644 (file)
@@ -1 +1 @@
-81ac8745faac0bda8d68ac113f1938f0e25208642e8ceb2af452680086454cb5
\ No newline at end of file
+141a93c843d501d8bb640228645ead0a83870c1c11e9d4b07ed24b296c69a0b8
\ No newline at end of file