Update the "changesetfuzz" program to work with patchsets as well as

changesets.

FossilOrigin-Name: 75b00fbe884d4bd8ba099d7c0a2e8af2f40fedfdef2d9b624dd51cb66952611c
This commit is contained in:
dan
2018-11-07 17:52:29 +00:00
parent 005d4c61c1
commit 7844d21536
3 changed files with 190 additions and 119 deletions
+183 -112
View File
@@ -86,11 +86,14 @@
** 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
** 14. A column may be removed from a table, provided that it is not the
** only PRIMARY KEY column in the 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.
** with no non-PK, non-undefined fields, the entire change is removed.
**
** PATCHSETS
**
** As well as changesets, this program can also dump and fuzz patchsets.
*/
#include "sqlite3.h"
@@ -118,13 +121,6 @@
#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_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 */
#endif
typedef unsigned char u8;
@@ -172,6 +168,10 @@ static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
*ppBuf = pBuf;
}
/*
** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename
** on disk. zFilename, if it already exists, is clobbered.
*/
static void fuzzWriteFile(const char *zFilename, void *pBuf, int nBuf){
FILE *f;
f = fopen(zFilename, "wb");
@@ -289,7 +289,6 @@ static void fuzzRandomSeed(unsigned int iSeed){
sqlite3Prng.s[i+3] ^= ((iSeed >> 0) & 0xFF);
}
}
/*
** End of code for generating pseudo-random values.
*************************************************************************/
@@ -298,12 +297,11 @@ typedef struct FuzzChangeset FuzzChangeset;
typedef struct FuzzChangesetGroup FuzzChangesetGroup;
typedef struct FuzzChange FuzzChange;
#define FUZZER_AVAL_SZ 512
/*
** Object containing partially parsed changeset.
*/
struct FuzzChangeset {
int bPatchset; /* True for a patchset */
FuzzChangesetGroup **apGroup; /* Array of groups in changeset */
int nGroup; /* Number of items in list pGroup */
u8 **apVal; /* Array of all values in changeset */
@@ -312,6 +310,10 @@ struct FuzzChangeset {
int nUpdate; /* Number of UPDATE changes in changeset */
};
/*
** There is one object of this type for each change-group (table header)
** in the input changeset.
*/
struct FuzzChangesetGroup {
const char *zTab; /* Name of table */
int nCol; /* Number of columns in table */
@@ -329,12 +331,15 @@ struct FuzzChange {
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 */
u8 *pSub1; /* Replace this value with pSub2 */
u8 *pSub2; /* And this one with pSub1 */
u8 aSub[128]; /* Buffer for substitute value */
int iCurrent; /* Current change number */
};
/*
** Allocate and return nByte bytes of zeroed memory.
*/
static void *fuzzMalloc(int nByte){
void *pRet = sqlite3_malloc(nByte);
if( pRet ){
@@ -343,10 +348,20 @@ static void *fuzzMalloc(int nByte){
return pRet;
}
/*
** Free the buffer indicated by the first argument. This function is used
** to free buffers allocated by fuzzMalloc().
*/
static void fuzzFree(void *p){
sqlite3_free(p);
}
/*
** Argument p points to a buffer containing an SQLite varint that, assuming the
** input is not corrupt, may be between 0 and 0x7FFFFFFF, inclusive. Before
** returning, this function sets (*pnVal) to the value of that varint, and
** returns the number of bytes of space that it takes up.
*/
static int fuzzGetVarint(u8 *p, int *pnVal){
int i;
sqlite3_uint64 nVal = 0;
@@ -361,6 +376,11 @@ static int fuzzGetVarint(u8 *p, int *pnVal){
return i;
}
/*
** Write value nVal into the buffer indicated by argument p as an SQLite
** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive.
** Return the number of bytes written to buffer p.
*/
static int fuzzPutVarint(u8 *p, int nVal){
assert( nVal>0 && nVal<2097152 );
if( nVal<128 ){
@@ -379,20 +399,26 @@ static int fuzzPutVarint(u8 *p, int nVal){
return 3;
}
/* Load an unaligned and unsigned 32-bit integer */
#define FUZZ_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
/*
** Read a 64-bit big-endian integer value from buffer aRec[]. Return
** the value read.
*/
static sqlite3_int64 fuzzGetI64(u8 *aRec){
u64 x = FUZZ_UINT32(aRec);
u32 y = FUZZ_UINT32(aRec+4);
x = (x<<32) + y;
return (sqlite3_int64)x;
static i64 fuzzGetI64(u8 *aRec){
return (i64)(
(((u64)aRec[0]) << 56)
+ (((u64)aRec[1]) << 48)
+ (((u64)aRec[2]) << 40)
+ (((u64)aRec[3]) << 32)
+ (((u64)aRec[4]) << 24)
+ (((u64)aRec[5]) << 16)
+ (((u64)aRec[6]) << 8)
+ (((u64)aRec[7]) << 0)
);
}
/*
** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer.
*/
static void fuzzPutU64(u8 *aRec, u64 iVal){
aRec[0] = (iVal>>56) & 0xFF;
aRec[1] = (iVal>>48) & 0xFF;
@@ -404,9 +430,15 @@ static void fuzzPutU64(u8 *aRec, u64 iVal){
aRec[7] = (iVal) & 0xFF;
}
static int fuzzParseHeader(u8 **ppHdr, u8 *pEnd, FuzzChangesetGroup **ppGrp){
static int fuzzParseHeader(
FuzzChangeset *pParse,
u8 **ppHdr,
u8 *pEnd,
FuzzChangesetGroup **ppGrp
){
int rc = SQLITE_OK;
FuzzChangesetGroup *pGrp;
u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
assert( pEnd>(*ppHdr) );
pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
@@ -414,7 +446,7 @@ static int fuzzParseHeader(u8 **ppHdr, u8 *pEnd, FuzzChangesetGroup **ppGrp){
rc = SQLITE_NOMEM;
}else{
u8 *p = *ppHdr;
if( p[0]!='T' ){
if( p[0]!=cHdr ){
rc = fuzzCorrupt();
}else{
p++;
@@ -468,26 +500,33 @@ static int fuzzChangeSize(u8 *p, int *pSz){
return SQLITE_OK;
}
static int fuzzParseRecord(u8 **ppRec, u8 *pEnd, FuzzChangeset *pParse){
static int fuzzParseRecord(
u8 **ppRec, /* IN/OUT: Iterator */
u8 *pEnd, /* One byte after end of input data */
FuzzChangeset *pParse,
int bPkOnly
){
int rc = SQLITE_OK;
int nCol = pParse->apGroup[pParse->nGroup-1]->nCol;
FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
int i;
u8 *p = *ppRec;
for(i=0; rc==SQLITE_OK && i<nCol && p<pEnd; i++){
int sz;
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;
for(i=0; rc==SQLITE_OK && i<pGrp->nCol && p<pEnd; i++){
if( bPkOnly==0 || pGrp->aPK[i] ){
int sz;
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;
}
pParse->apVal[pParse->nVal++] = p;
rc = fuzzChangeSize(p, &sz);
p += sz;
}
if( rc==SQLITE_OK && i<nCol ){
if( rc==SQLITE_OK && i<pGrp->nCol ){
rc = fuzzCorrupt();
}
@@ -496,24 +535,28 @@ static int fuzzParseRecord(u8 **ppRec, u8 *pEnd, FuzzChangeset *pParse){
}
static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
int rc = SQLITE_OK;
u8 *p = *ppData;
pGrp->aChange = p;
while( rc==SQLITE_OK && p<pEnd && p[0]!='T' ){
while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){
u8 eOp = p[0];
u8 bIndirect = p[1];
p += 2;
if( eOp==SQLITE_UPDATE ){
pParse->nUpdate++;
rc = fuzzParseRecord(&p, pEnd, pParse);
if( pParse->bPatchset==0 ){
rc = fuzzParseRecord(&p, pEnd, pParse, 0);
}
}else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
rc = fuzzCorrupt();
}
if( rc==SQLITE_OK ){
rc = fuzzParseRecord(&p, pEnd, pParse);
int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset);
rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly);
}
pGrp->nChange++;
pParse->nChange++;
@@ -534,16 +577,19 @@ static int fuzzParseChangeset(
int rc = SQLITE_OK;
memset(pParse, 0, sizeof(FuzzChangeset));
if( nChangeset>0 ){
pParse->bPatchset = (pChangeset[0]=='P');
}
while( rc==SQLITE_OK && p<pEnd ){
FuzzChangesetGroup *pGrp = 0;
/* Read a table-header from the changeset */
rc = fuzzParseHeader(&p, pEnd, &pGrp);
rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp);
assert( (rc==SQLITE_OK)==(pGrp!=0) );
/* If the table-header was successfully parsed, link the new change-group
** into the linked list and parse the associated array of changes. */
/* If the table-header was successfully parsed, add the new change-group
** to the array and parse the associated changes. */
if( rc==SQLITE_OK ){
FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc(
pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
@@ -562,65 +608,67 @@ static int fuzzParseChangeset(
return rc;
}
static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec){
static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
int rc = SQLITE_OK;
u8 *p = *ppRec;
int i;
const char *zPre = " (";
for(i=0; i<pGrp->nCol; i++){
u8 eType = p++[0];
switch( eType ){
case 0x00: /* undefined */
printf("%sn/a", zPre);
break;
if( bPKOnly==0 || pGrp->aPK[i] ){
u8 eType = p++[0];
switch( eType ){
case 0x00: /* undefined */
printf("%sn/a", zPre);
break;
case 0x01: { /* integer */
sqlite3_int64 iVal = 0;
iVal = fuzzGetI64(p);
printf("%s%lld", zPre, iVal);
p += 8;
break;
}
case 0x02: { /* real */
sqlite3_int64 iVal = 0;
double fVal = 0.0;
iVal = fuzzGetI64(p);
memcpy(&fVal, &iVal, 8);
printf("%s%f", zPre, fVal);
p += 8;
break;
}
case 0x03: /* text */
case 0x04: { /* blob */
int nTxt;
int sz;
int i;
p += fuzzGetVarint(p, &nTxt);
printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
for(i=0; i<nTxt; i++){
if( eType==0x03 ){
printf("%c", p[i]);
}else{
char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
printf("%c", aHex[ p[i]>>4 ]);
printf("%c", aHex[ p[i] & 0x0F ]);
}
case 0x01: { /* integer */
sqlite3_int64 iVal = 0;
iVal = fuzzGetI64(p);
printf("%s%lld", zPre, iVal);
p += 8;
break;
}
printf("'");
p += nTxt;
break;
}
case 0x05: /* null */
printf("%sNULL", zPre);
break;
case 0x02: { /* real */
sqlite3_int64 iVal = 0;
double fVal = 0.0;
iVal = fuzzGetI64(p);
memcpy(&fVal, &iVal, 8);
printf("%s%f", zPre, fVal);
p += 8;
break;
}
case 0x03: /* text */
case 0x04: { /* blob */
int nTxt;
int sz;
int i;
p += fuzzGetVarint(p, &nTxt);
printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
for(i=0; i<nTxt; i++){
if( eType==0x03 ){
printf("%c", p[i]);
}else{
char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
printf("%c", aHex[ p[i]>>4 ]);
printf("%c", aHex[ p[i] & 0x0F ]);
}
}
printf("'");
p += nTxt;
break;
}
case 0x05: /* null */
printf("%sNULL", zPre);
break;
}
zPre = ", ";
}
zPre = ", ";
}
printf(")");
@@ -628,7 +676,7 @@ static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec){
return rc;
}
static int fuzzPrintGroup(FuzzChangesetGroup *pGrp){
static int fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
int i;
u8 *p;
@@ -651,10 +699,10 @@ static int fuzzPrintGroup(FuzzChangesetGroup *pGrp){
);
p += 2;
if( eType==SQLITE_UPDATE ){
fuzzPrintRecord(pGrp, &p);
if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){
fuzzPrintRecord(pGrp, &p, 0);
}
fuzzPrintRecord(pGrp, &p);
fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
printf("\n");
}
}
@@ -663,7 +711,7 @@ static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
int iSub;
memset(pChange, 0, sizeof(FuzzChange));
pChange->eType = fuzzRandomInt(14) + FUZZ_VALUE_SUB;
pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1;
assert( pChange->eType==FUZZ_VALUE_SUB
|| pChange->eType==FUZZ_VALUE_MOD
@@ -795,12 +843,13 @@ static int fuzzCopyChange(
FuzzChange *pFuzz,
u8 **pp, u8 **ppOut /* IN/OUT: Input and output pointers */
){
int bPS = pParse->bPatchset;
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 nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1);
int iUndef = -1;
int nUpdate = 0;
@@ -833,6 +882,7 @@ static int fuzzCopyChange(
}
if( nDef<=1 ) return -1;
nDef = fuzzRandomInt(nDef);
pCsr = p+1;
for(i=0; i<pGrp->nCol; i++){
if( pCsr[0] && pGrp->aPK[i]==0 ){
if( nDef==0 ) iUndef = i;
@@ -855,10 +905,30 @@ static int fuzzCopyChange(
for(iRec=0; iRec<nRec; iRec++){
int i;
/* Copy the next record from the output to the input.
*/
for(i=0; i<pGrp->nCol; i++){
int sz;
u8 *pCopy = p;
/* If this is a patchset, and the input is a DELETE, then the only
** fields present are the PK fields. So, if this is not a PK, skip to
** the next column. If the current fuzz is FUZZ_CHANGE_TYPE, then
** write a randomly selected value to the output. */
if( bPS && eType==SQLITE_DELETE && pGrp->aPK[i]==0 ){
if( eType!=eNew ){
assert( eNew==SQLITE_UPDATE );
do {
pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
}while( pCopy[0]==0x00 );
fuzzChangeSize(pCopy, &sz);
memcpy(pOut, pCopy, sz);
pOut += sz;
}
continue;
}
if( p==pFuzz->pSub1 ){
pCopy = pFuzz->pSub2;
}else if( p==pFuzz->pSub2 ){
@@ -877,13 +947,14 @@ static int fuzzCopyChange(
if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
}
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);
}
if( (pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete)
&& (eNew==eType || eType!=SQLITE_UPDATE || iRec==0)
&& (eNew==eType || eNew!=SQLITE_DELETE || !bPS || pGrp->aPK[i])
){
fuzzChangeSize(pCopy, &sz);
memcpy(pOut, pCopy, sz);
pOut += sz;
nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
}
fuzzChangeSize(p, &sz);
@@ -892,7 +963,7 @@ static int fuzzCopyChange(
if( iGrp==pFuzz->iGroup ){
if( pFuzz->eType==FUZZ_COLUMN_ADD ){
*(pOut++) = 0x05;
if( !bPS || eType!=SQLITE_DELETE ) *(pOut++) = 0x05;
}else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
if( iRec==1 ){
*(pOut++) = 0x00;
@@ -920,7 +991,7 @@ static int fuzzCopyChange(
if( pFuzz->eType==FUZZ_CHANGE_DEL ){
pOut = *ppOut;
}
if( eNew!=eType && eNew==SQLITE_UPDATE ){
if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){
int i;
u8 *pCsr = (*ppOut) + 2;
for(i=0; i<pGrp->nCol; i++){
@@ -1003,7 +1074,7 @@ static int fuzzDoOneFuzz(
}
/* Output a table header */
pOut++[0] = 'T';
pOut++[0] = pParse->bPatchset ? 'P' : 'T';
pOut += fuzzPutVarint(pOut, nCol);
for(i=0; i<pGrp->nCol; i++){
@@ -1063,7 +1134,7 @@ int main(int argc, char **argv){
if( rc==SQLITE_OK ){
if( argc==2 ){
for(i=0; i<changeset.nGroup; i++){
fuzzPrintGroup(changeset.apGroup[i]);
fuzzPrintGroup(&changeset, changeset.apGroup[i]);
}
}else{
pBuf = (u8*)fuzzMalloc(nChangeset*2 + 1024);
+6 -6
View File
@@ -1,5 +1,5 @@
C Update\sthe\schangesetfuzz\sprogram\sto\sfuzz\schangeset\sschemas\sas\swell\sas\sdata.
D 2018-11-06T20:08:03.912
C Update\sthe\s"changesetfuzz"\sprogram\sto\swork\swith\spatchsets\sas\swell\sas\nchangesets.
D 2018-11-07T17:52:29.921
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 27aec2e060043eb7377d7075e20959c85c57a41f4f72c30f8bace12cc9b9af69
F ext/session/changesetfuzz.c 8b4f3091f6414e670c3a8612a1095408a1799a7a6375ff44f2304252859da261
F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e
F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
@@ -1777,7 +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 81ac8745faac0bda8d68ac113f1938f0e25208642e8ceb2af452680086454cb5
R 2ce6a540d3c541564d5607a6269445d4
P 141a93c843d501d8bb640228645ead0a83870c1c11e9d4b07ed24b296c69a0b8
R 4289a808fad84891b491838dfee569e3
U dan
Z 7a3bd8208ab7b3ca6eb82773978332aa
Z e21072c848321b1c17525b7d97cbc80a
+1 -1
View File
@@ -1 +1 @@
141a93c843d501d8bb640228645ead0a83870c1c11e9d4b07ed24b296c69a0b8
75b00fbe884d4bd8ba099d7c0a2e8af2f40fedfdef2d9b624dd51cb66952611c