/ Check-in [5c7f0240]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix minor issues in the changesetfuzz program.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | changesetfuzz
Files: files | file ages | folders
SHA3-256:5c7f024073bc93089f038b5cf122a7a9d5b933f7c1b357f6d20ae925739ffc38
User & Date: dan 2018-11-07 20:07:28
Context
2018-11-07
20:13
Merge latest trunk changes into this branch. check-in: 53cd91d0 user: dan tags: changesetfuzz
20:07
Fix minor issues in the changesetfuzz program. check-in: 5c7f0240 user: dan tags: changesetfuzz
17:52
Update the "changesetfuzz" program to work with patchsets as well as changesets. check-in: 75b00fbe user: dan tags: changesetfuzz
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/session/changesetfuzz.c.

    21     21   **
    22     22   **   changesetfuzz INPUT
    23     23   **   changesetfuzz INPUT SEED N
    24     24   **
    25     25   ** Argument INPUT must be the name of a file containing a binary changeset.
    26     26   ** In the first form above, this program outputs a human-readable version
    27     27   ** of the same changeset. This is chiefly for debugging.
           28  +**
           29  +** As well as changesets, this program can also dump and fuzz patchsets.
           30  +** The term "changeset" is used for both patchsets and changesets from this
           31  +** point on.
    28     32   **
    29     33   ** In the second form, arguments SEED and N must both be integers. In this
    30     34   ** case, this program writes N binary changesets to disk. Each output
    31     35   ** changeset is a slightly modified - "fuzzed" - version of the input. 
    32     36   ** The output changesets are written to files name "INPUT-$n", where $n is 
    33     37   ** an integer between 0 and N-1, inclusive. Output changesets are always
    34     38   ** well-formed. Parameter SEED is used to seed the PRNG - any two 
................................................................................
    86     90   **      value is appended to all INSERT, DELETE and UPDATE old.* records.
    87     91   **      An "undefined" is appended to new.* UPDATE records.
    88     92   **
    89     93   **  14. A column may be removed from a table, provided that it is not the
    90     94   **      only PRIMARY KEY column in the table. In this case the corresponding
    91     95   **      field is removed from all records. In cases where this leaves an UPDATE
    92     96   **      with no non-PK, non-undefined fields, the entire change is removed.
    93         -**
    94         -** PATCHSETS
    95         -**
    96         -** As well as changesets, this program can also dump and fuzz patchsets.
    97     97   */
    98     98   
    99     99   #include "sqlite3.h"
   100    100   #include <stdio.h>
   101    101   #include <stdlib.h>
   102    102   #include <string.h>
   103    103   #include <assert.h>
................................................................................
   426    426     aRec[3] = (iVal>>32) & 0xFF;
   427    427     aRec[4] = (iVal>>24) & 0xFF;
   428    428     aRec[5] = (iVal>>16) & 0xFF;
   429    429     aRec[6] = (iVal>> 8) & 0xFF;
   430    430     aRec[7] = (iVal)     & 0xFF;
   431    431   }
   432    432   
          433  +/*
          434  +** Parse a single table-header from the input. Allocate a new change-group
          435  +** object with the results. Return SQLITE_OK if successful, or an error code
          436  +** otherwise.
          437  +*/
   433    438   static int fuzzParseHeader(
   434         -  FuzzChangeset *pParse,
   435         -  u8 **ppHdr, 
   436         -  u8 *pEnd, 
   437         -  FuzzChangesetGroup **ppGrp
          439  +  FuzzChangeset *pParse,          /* Changeset parse object */
          440  +  u8 **ppHdr,                     /* IN/OUT: Iterator */
          441  +  u8 *pEnd,                       /* 1 byte past EOF */
          442  +  FuzzChangesetGroup **ppGrp      /* OUT: New change-group object */
   438    443   ){
   439    444     int rc = SQLITE_OK;
   440    445     FuzzChangesetGroup *pGrp;
   441    446     u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
   442    447   
   443    448     assert( pEnd>(*ppHdr) );
   444    449     pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
................................................................................
   468    473       pGrp = 0;
   469    474     }
   470    475   
   471    476     *ppGrp = pGrp;
   472    477     return rc;
   473    478   }
   474    479   
          480  +/*
          481  +** Argument p points to a buffer containing a single changeset-record value. 
          482  +** This function attempts to determine the size of the value in bytes. If
          483  +** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the
          484  +** buffer does not contain a valid value, SQLITE_CORRUPT is returned and
          485  +** the final value of (*pSz) is undefined.
          486  +*/
   475    487   static int fuzzChangeSize(u8 *p, int *pSz){
   476    488     u8 eType = p[0];
   477    489     switch( eType ){
   478    490       case 0x00:                    /* undefined */
   479    491       case 0x05:                    /* null */
   480    492         *pSz = 1;
   481    493         break;
................................................................................
   496    508   
   497    509       default:
   498    510         return fuzzCorrupt();
   499    511     }
   500    512     return SQLITE_OK;
   501    513   }
   502    514   
          515  +/*
          516  +** When this function is called, (*ppRec) points to the start of a 
          517  +** record in a changeset being parsed. This function adds entries
          518  +** to the pParse->apVal[] array for all values and advances (*ppRec) 
          519  +** to one byte past the end of the record. Argument pEnd points to
          520  +** one byte past the end of the input changeset.
          521  +**
          522  +** Argument bPkOnly is true if the record being parsed is part of
          523  +** a DELETE record in a patchset. In this case, all non-primary-key
          524  +** fields have been omitted from the record.
          525  +**
          526  +** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
          527  +*/
   503    528   static int fuzzParseRecord(
   504    529     u8 **ppRec,                     /* IN/OUT: Iterator */
   505    530     u8 *pEnd,                       /* One byte after end of input data */
   506         -  FuzzChangeset *pParse,
   507         -  int bPkOnly
          531  +  FuzzChangeset *pParse,          /* Changeset parse context */
          532  +  int bPkOnly                     /* True if non-PK fields omitted */
   508    533   ){
   509    534     int rc = SQLITE_OK;
   510    535     FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
   511    536     int i;
   512    537     u8 *p = *ppRec;
   513    538   
   514    539     for(i=0; rc==SQLITE_OK && i<pGrp->nCol && p<pEnd; i++){
................................................................................
   530    555       rc = fuzzCorrupt();
   531    556     }
   532    557   
   533    558     *ppRec = p;
   534    559     return rc;
   535    560   }
   536    561   
          562  +/*
          563  +** Parse the array of changes starting at (*ppData) and add entries for
          564  +** all values to the pParse->apVal[] array. Argument pEnd points to one byte
          565  +** past the end of the input changeset. If successful, set (*ppData) to point
          566  +** to one byte past the end of the change array and return SQLITE_OK.
          567  +** Otherwise, return an SQLite error code. The final value of (*ppData) is
          568  +** undefined in this case.
          569  +*/
   537    570   static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
   538    571     u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
   539    572     FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
   540    573     int rc = SQLITE_OK;
   541    574     u8 *p = *ppData;
   542    575   
   543    576     pGrp->aChange = p;
................................................................................
   563    596     }
   564    597     pGrp->szChange = p - pGrp->aChange;
   565    598   
   566    599     *ppData = p;
   567    600     return rc;
   568    601   }
   569    602   
          603  +/*
          604  +** Parse the changeset stored in buffer pChangeset (nChangeset bytes in
          605  +** size). If successful, write the results into (*pParse) and return
          606  +** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The
          607  +** final state of (*pParse) is undefined in this case.
          608  +*/
   570    609   static int fuzzParseChangeset(
   571    610     u8 *pChangeset,                 /* Buffer containing changeset */
   572    611     int nChangeset,                 /* Size of buffer in bytes */
   573    612     FuzzChangeset *pParse           /* OUT: Results of parse */
   574    613   ){
   575    614     u8 *pEnd = &pChangeset[nChangeset];
   576    615     u8 *p = pChangeset;
................................................................................
   604    643         rc = fuzzParseChanges(&p, pEnd, pParse);
   605    644       }
   606    645     }
   607    646   
   608    647     return rc;
   609    648   }
   610    649   
          650  +/*
          651  +** When this function is called, (*ppRec) points to the first byte of
          652  +** a record that is part of change-group pGrp. This function attempts
          653  +** to output a human-readable version of the record to stdout and advance
          654  +** (*ppRec) to point to the first byte past the end of the record before
          655  +** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite
          656  +** error code.
          657  +**
          658  +** If parameter bPkOnly is non-zero, then all non-primary-key fields have
          659  +** been omitted from the record. This occurs for records that are part
          660  +** of DELETE changes in patchsets.
          661  +*/
   611    662   static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
   612    663     int rc = SQLITE_OK;
   613    664     u8 *p = *ppRec;
   614    665     int i;
   615    666     const char *zPre = " (";
   616    667   
   617    668     for(i=0; i<pGrp->nCol; i++){
................................................................................
   672    723     }
   673    724     printf(")");
   674    725   
   675    726     *ppRec = p;
   676    727     return rc;
   677    728   }
   678    729   
   679         -static int fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
          730  +/*
          731  +** Print a human-readable version of the table-header and all changes in the
          732  +** change-group passed as the second argument.
          733  +*/
          734  +static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
   680    735     int i;
   681    736     u8 *p;
   682    737   
   683    738     /* The table header */
   684    739     printf("TABLE:  %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol);
   685    740     for(i=0; i<pGrp->nCol; i++){
   686    741       printf("%d", (int)pGrp->aPK[i]);
................................................................................
   703    758         fuzzPrintRecord(pGrp, &p, 0);
   704    759       }
   705    760       fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
   706    761       printf("\n");
   707    762     }
   708    763   }
   709    764   
          765  +/*
          766  +** Initialize the object passed as the second parameter with details
          767  +** of the change that will be attempted (type of change, to which part of the
          768  +** changeset it applies etc.). If successful, return SQLITE_OK. Or, if an
          769  +** error occurs, return an SQLite error code. 
          770  +**
          771  +** If a negative value is returned, then the selected change would have
          772  +** produced a non-well-formed changeset. In this case the caller should
          773  +** call this function again.
          774  +*/
   710    775   static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
   711    776     int iSub;
   712    777   
   713    778     memset(pChange, 0, sizeof(FuzzChange));
   714    779     pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1;
   715    780   
   716    781     assert( pChange->eType==FUZZ_VALUE_SUB
................................................................................
   833    898         }
   834    899       }
   835    900     }
   836    901   
   837    902     return SQLITE_OK;
   838    903   }
   839    904   
          905  +/*
          906  +** Copy a single change from the input to the output changeset, making
          907  +** any modifications specified by (*pFuzz).
          908  +*/
   840    909   static int fuzzCopyChange(
   841    910     FuzzChangeset *pParse,
   842    911     int iGrp,
   843    912     FuzzChange *pFuzz,
   844    913     u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
   845    914   ){
   846    915     int bPS = pParse->bPatchset;
................................................................................
  1018   1087   
  1019   1088     *pp = p;
  1020   1089     *ppOut = pOut;
  1021   1090     pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
  1022   1091     return SQLITE_OK;
  1023   1092   }
  1024   1093   
         1094  +/*
         1095  +** Fuzz the changeset parsed into object pParse and write the results 
         1096  +** to file zOut on disk. Argument pBuf points to a buffer that is guaranteed
         1097  +** to be large enough to hold the fuzzed changeset.
         1098  +**
         1099  +** Return SQLITE_OK if successful, or an SQLite error code if an error occurs.
         1100  +*/
  1025   1101   static int fuzzDoOneFuzz(
  1026   1102     const char *zOut,               /* Filename to write modified changeset to */
  1027   1103     u8 *pBuf,                       /* Buffer to use for modified changeset */
  1028   1104     FuzzChangeset *pParse           /* Parse of input changeset */
  1029   1105   ){
  1030   1106     FuzzChange change;
  1031   1107     int iGrp;