4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
12 ** This file contains code to implement the "changesetfuzz" command
13 ** line utility for fuzzing changeset blobs without corrupting them.
17 /************************************************************************
20 ** This program may be invoked in two ways:
22 ** changesetfuzz INPUT
23 ** changesetfuzz INPUT SEED N
25 ** Argument INPUT must be the name of a file containing a binary changeset.
26 ** In the first form above, this program outputs a human-readable version
27 ** of the same changeset. This is chiefly for debugging.
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
33 ** In the second form, arguments SEED and N must both be integers. In this
34 ** case, this program writes N binary changesets to disk. Each output
35 ** changeset is a slightly modified - "fuzzed" - version of the input.
36 ** The output changesets are written to files name "INPUT-$n", where $n is
37 ** an integer between 0 and N-1, inclusive. Output changesets are always
38 ** well-formed. Parameter SEED is used to seed the PRNG - any two
39 ** invocations of this program with the same SEED and input changeset create
40 ** the same N output changesets.
42 ** The ways in which an input changeset may be fuzzed are as follows:
44 ** 1. Any two values within the changeset may be exchanged.
46 ** 2. Any TEXT, BLOB, INTEGER or REAL value within the changeset
47 ** may have a single bit of its content flipped.
49 ** 3. Any value within a changeset may be replaced by a pseudo-randomly
52 ** The above operations never set a PRIMARY KEY column to NULL. Nor do they
53 ** set any value to "undefined", or replace any "undefined" value with
54 ** another. Any such operation risks producing a changeset that is not
57 ** 4. A single change may be duplicated.
59 ** 5. A single change may be removed, so long as this does not mean that
60 ** there are zero changes following a table-header within the changeset.
62 ** 6. A single change may have its type (INSERT, DELETE, UPDATE) changed.
63 ** If an INSERT is changed to a DELETE (or vice versa), the type is
64 ** simply changed - no other modifications are required. If an INSERT
65 ** or DELETE is changed to an UPDATE, then the single record is duplicated
66 ** (as both the old.* and new.* records of the new UPDATE change). If an
67 ** UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
68 ** and any "undefined" fields replaced with pseudo-randomly generated
71 ** 7. An UPDATE change that modifies N table columns may be modified so
72 ** that it updates N-1 columns, so long as (N>1).
74 ** 8. The "indirect" flag may be toggled for any change.
76 ** Entire group of changes may also be operated on:
78 ** 9. Duplicate an existing group.
80 ** 10. Remove an existing group.
82 ** 11. The positions of two groups may be exchanged.
84 ** There are also schema changes:
86 ** 12. A non-PK column may be added to a table. In this case a NULL
87 ** value is appended to all records.
89 ** 13. A PK column may be added to a table. In this case a non-NULL
90 ** value is appended to all INSERT, DELETE and UPDATE old.* records.
91 ** An "undefined" is appended to new.* UPDATE records.
93 ** 14. A column may be removed from a table, provided that it is not the
94 ** only PRIMARY KEY column in the table. In this case the corresponding
95 ** field is removed from all records. In cases where this leaves an UPDATE
96 ** with no non-PK, non-undefined fields, the entire change is removed.
106 #define FUZZ_VALUE_SUB 1 /* Replace one value with a copy of another */
107 #define FUZZ_VALUE_MOD 2 /* Modify content by 1 bit */
108 #define FUZZ_VALUE_RND 3 /* Replace with pseudo-random value */
110 #define FUZZ_CHANGE_DUP 4 /* Duplicate an existing change */
111 #define FUZZ_CHANGE_DEL 5 /* Completely remove one change */
112 #define FUZZ_CHANGE_TYPE 6 /* Change the type of one change */
113 #define FUZZ_CHANGE_FIELD 7 /* Change an UPDATE to modify fewer columns */
114 #define FUZZ_CHANGE_INDIRECT 8 /* Toggle the "indirect" flag of a change */
116 #define FUZZ_GROUP_DUP 9 /* Duplicate a change group */
117 #define FUZZ_GROUP_DEL 10 /* Delete an entire change group */
118 #define FUZZ_GROUP_SWAP 11 /* Exchange the position of two groups */
120 #define FUZZ_COLUMN_ADD 12 /* Add column to table definition */
121 #define FUZZ_COLUMN_ADDPK 13 /* Add PK column to table definition */
122 #define FUZZ_COLUMN_DEL 14 /* Remove column from table definition */
126 typedef unsigned char u8
;
127 typedef sqlite3_uint64 u64
;
128 typedef sqlite3_int64 i64
;
129 typedef unsigned int u32
;
132 ** Show a usage message on stderr then quit.
134 static void usage(const char *argv0
){
135 fprintf(stderr
, "Usage: %s FILENAME ?SEED N?\n", argv0
);
140 ** Read the content of a disk file into an in-memory buffer
142 static void fuzzReadFile(const char *zFilename
, int *pSz
, void **ppBuf
){
146 f
= fopen(zFilename
, "rb");
148 fprintf(stderr
, "cannot open \"%s\" for reading\n", zFilename
);
151 fseek(f
, 0, SEEK_END
);
154 pBuf
= sqlite3_malloc64( sz
? sz
: 1 );
156 fprintf(stderr
, "cannot allocate %d to hold content of \"%s\"\n",
161 if( fread(pBuf
, (size_t)sz
, 1, f
)!=1 ){
162 fprintf(stderr
, "cannot read all %d bytes of \"%s\"\n",
173 ** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename
174 ** on disk. zFilename, if it already exists, is clobbered.
176 static void fuzzWriteFile(const char *zFilename
, void *pBuf
, int nBuf
){
178 f
= fopen(zFilename
, "wb");
180 fprintf(stderr
, "cannot open \"%s\" for writing\n", zFilename
);
183 if( fwrite(pBuf
, nBuf
, 1, f
)!=1 ){
184 fprintf(stderr
, "cannot write to \"%s\"\n", zFilename
);
190 static int fuzzCorrupt(){
191 return SQLITE_CORRUPT
;
194 /*************************************************************************
195 ** The following block is a copy of the implementation of SQLite function
196 ** sqlite3_randomness. This version has two important differences:
198 ** 1. It always uses the same seed. So the sequence of random data output
199 ** is the same for every run of the program.
201 ** 2. It is not threadsafe.
203 static struct sqlite3PrngType
{
204 unsigned char i
, j
; /* State variables */
205 unsigned char s
[256]; /* State variables */
209 0x71, 0xF5, 0xB4, 0x6E, 0x80, 0xAB, 0x1D, 0xB8,
210 0xFB, 0xB7, 0x49, 0xBF, 0xFF, 0x72, 0x2D, 0x14,
211 0x79, 0x09, 0xE3, 0x78, 0x76, 0xB0, 0x2C, 0x0A,
212 0x8E, 0x23, 0xEE, 0xDF, 0xE0, 0x9A, 0x2F, 0x67,
213 0xE1, 0xBE, 0x0E, 0xA7, 0x08, 0x97, 0xEB, 0x77,
214 0x78, 0xBA, 0x9D, 0xCA, 0x49, 0x4C, 0x60, 0x9A,
215 0xF6, 0xBD, 0xDA, 0x7F, 0xBC, 0x48, 0x58, 0x52,
216 0xE5, 0xCD, 0x83, 0x72, 0x23, 0x52, 0xFF, 0x6D,
217 0xEF, 0x0F, 0x82, 0x29, 0xA0, 0x83, 0x3F, 0x7D,
218 0xA4, 0x88, 0x31, 0xE7, 0x88, 0x92, 0x3B, 0x9B,
219 0x3B, 0x2C, 0xC2, 0x4C, 0x71, 0xA2, 0xB0, 0xEA,
220 0x36, 0xD0, 0x00, 0xF1, 0xD3, 0x39, 0x17, 0x5D,
221 0x2A, 0x7A, 0xE4, 0xAD, 0xE1, 0x64, 0xCE, 0x0F,
222 0x9C, 0xD9, 0xF5, 0xED, 0xB0, 0x22, 0x5E, 0x62,
223 0x97, 0x02, 0xA3, 0x8C, 0x67, 0x80, 0xFC, 0x88,
224 0x14, 0x0B, 0x15, 0x10, 0x0F, 0xC7, 0x40, 0xD4,
225 0xF1, 0xF9, 0x0E, 0x1A, 0xCE, 0xB9, 0x1E, 0xA1,
226 0x72, 0x8E, 0xD7, 0x78, 0x39, 0xCD, 0xF4, 0x5D,
227 0x2A, 0x59, 0x26, 0x34, 0xF2, 0x73, 0x0B, 0xA0,
228 0x02, 0x51, 0x2C, 0x03, 0xA3, 0xA7, 0x43, 0x13,
229 0xE8, 0x98, 0x2B, 0xD2, 0x53, 0xF8, 0xEE, 0x91,
230 0x7D, 0xE7, 0xE3, 0xDA, 0xD5, 0xBB, 0xC0, 0x92,
231 0x9D, 0x98, 0x01, 0x2C, 0xF9, 0xB9, 0xA0, 0xEB,
232 0xCF, 0x32, 0xFA, 0x01, 0x49, 0xA5, 0x1D, 0x9A,
233 0x76, 0x86, 0x3F, 0x40, 0xD4, 0x89, 0x8F, 0x9C,
234 0xE2, 0xE3, 0x11, 0x31, 0x37, 0xB2, 0x49, 0x28,
235 0x35, 0xC0, 0x99, 0xB6, 0xD0, 0xBC, 0x66, 0x35,
236 0xF7, 0x83, 0x5B, 0xD7, 0x37, 0x1A, 0x2B, 0x18,
237 0xA6, 0xFF, 0x8D, 0x7C, 0x81, 0xA8, 0xFC, 0x9E,
238 0xC4, 0xEC, 0x80, 0xD0, 0x98, 0xA7, 0x76, 0xCC,
239 0x9C, 0x2F, 0x7B, 0xFF, 0x8E, 0x0E, 0xBB, 0x90,
240 0xAE, 0x13, 0x06, 0xF5, 0x1C, 0x4E, 0x52, 0xF7
245 ** Generate and return single random byte
247 static unsigned char fuzzRandomByte(void){
250 t
= sqlite3Prng
.s
[sqlite3Prng
.i
];
252 sqlite3Prng
.s
[sqlite3Prng
.i
] = sqlite3Prng
.s
[sqlite3Prng
.j
];
253 sqlite3Prng
.s
[sqlite3Prng
.j
] = t
;
254 t
+= sqlite3Prng
.s
[sqlite3Prng
.i
];
255 return sqlite3Prng
.s
[t
];
259 ** Return N random bytes.
261 static void fuzzRandomBlob(int nBuf
, unsigned char *zBuf
){
263 for(i
=0; i
<nBuf
; i
++){
264 zBuf
[i
] = fuzzRandomByte();
269 ** Return a random integer between 0 and nRange (not inclusive).
271 static unsigned int fuzzRandomInt(unsigned int nRange
){
274 fuzzRandomBlob(sizeof(ret
), (unsigned char*)&ret
);
275 return (ret
% nRange
);
278 static u64
fuzzRandomU64(){
280 fuzzRandomBlob(sizeof(ret
), (unsigned char*)&ret
);
284 static void fuzzRandomSeed(unsigned int iSeed
){
286 for(i
=0; i
<256; i
+=4){
287 sqlite3Prng
.s
[i
] ^= ((iSeed
>> 24) & 0xFF);
288 sqlite3Prng
.s
[i
+1] ^= ((iSeed
>> 16) & 0xFF);
289 sqlite3Prng
.s
[i
+2] ^= ((iSeed
>> 8) & 0xFF);
290 sqlite3Prng
.s
[i
+3] ^= ((iSeed
>> 0) & 0xFF);
294 ** End of code for generating pseudo-random values.
295 *************************************************************************/
297 typedef struct FuzzChangeset FuzzChangeset
;
298 typedef struct FuzzChangesetGroup FuzzChangesetGroup
;
299 typedef struct FuzzChange FuzzChange
;
302 ** Object containing partially parsed changeset.
304 struct FuzzChangeset
{
305 int bPatchset
; /* True for a patchset */
306 FuzzChangesetGroup
**apGroup
; /* Array of groups in changeset */
307 int nGroup
; /* Number of items in list pGroup */
308 u8
**apVal
; /* Array of all values in changeset */
309 int nVal
; /* Number of used slots in apVal[] */
310 int nChange
; /* Number of changes in changeset */
311 int nUpdate
; /* Number of UPDATE changes in changeset */
315 ** There is one object of this type for each change-group (table header)
316 ** in the input changeset.
318 struct FuzzChangesetGroup
{
319 const char *zTab
; /* Name of table */
320 int nCol
; /* Number of columns in table */
321 u8
*aPK
; /* PK array for this table */
322 u8
*aChange
; /* Buffer containing array of changes */
323 int szChange
; /* Size of buffer aChange[] in bytes */
324 int nChange
; /* Number of changes in buffer aChange[] */
328 ** Description of a fuzz change to be applied to a changeset.
331 int eType
; /* One of the FUZZ_* constants above */
332 int iChange
; /* Change or UPDATE to modify */
333 int iGroup
; /* Group to modify */
334 int iDelete
; /* Field to remove (FUZZ_COLUMN_DEL) */
335 u8
*pSub1
; /* Replace this value with pSub2 */
336 u8
*pSub2
; /* And this one with pSub1 */
337 u8 aSub
[128]; /* Buffer for substitute value */
338 int iCurrent
; /* Current change number */
342 ** Allocate and return nByte bytes of zeroed memory.
344 static void *fuzzMalloc(sqlite3_int64 nByte
){
345 void *pRet
= sqlite3_malloc64(nByte
);
347 memset(pRet
, 0, (size_t)nByte
);
353 ** Free the buffer indicated by the first argument. This function is used
354 ** to free buffers allocated by fuzzMalloc().
356 static void fuzzFree(void *p
){
361 ** Argument p points to a buffer containing an SQLite varint that, assuming the
362 ** input is not corrupt, may be between 0 and 0x7FFFFFFF, inclusive. Before
363 ** returning, this function sets (*pnVal) to the value of that varint, and
364 ** returns the number of bytes of space that it takes up.
366 static int fuzzGetVarint(u8
*p
, int *pnVal
){
368 sqlite3_uint64 nVal
= 0;
370 nVal
= (nVal
<<7) + (p
[i
] & 0x7F);
371 if( (p
[i
] & 0x80)==0 ){
381 ** Write value nVal into the buffer indicated by argument p as an SQLite
382 ** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive.
383 ** Return the number of bytes written to buffer p.
385 static int fuzzPutVarint(u8
*p
, int nVal
){
386 assert( nVal
>0 && nVal
<2097152 );
392 p
[0] = ((nVal
>> 7) & 0x7F) | 0x80;
393 p
[1] = (nVal
& 0x7F);
397 p
[0] = ((nVal
>> 14) & 0x7F) | 0x80;
398 p
[1] = ((nVal
>> 7) & 0x7F) | 0x80;
399 p
[2] = (nVal
& 0x7F);
404 ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
407 static i64
fuzzGetI64(u8
*aRec
){
409 (((u64
)aRec
[0]) << 56)
410 + (((u64
)aRec
[1]) << 48)
411 + (((u64
)aRec
[2]) << 40)
412 + (((u64
)aRec
[3]) << 32)
413 + (((u64
)aRec
[4]) << 24)
414 + (((u64
)aRec
[5]) << 16)
415 + (((u64
)aRec
[6]) << 8)
416 + (((u64
)aRec
[7]) << 0)
421 ** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer.
423 static void fuzzPutU64(u8
*aRec
, u64 iVal
){
424 aRec
[0] = (iVal
>>56) & 0xFF;
425 aRec
[1] = (iVal
>>48) & 0xFF;
426 aRec
[2] = (iVal
>>40) & 0xFF;
427 aRec
[3] = (iVal
>>32) & 0xFF;
428 aRec
[4] = (iVal
>>24) & 0xFF;
429 aRec
[5] = (iVal
>>16) & 0xFF;
430 aRec
[6] = (iVal
>> 8) & 0xFF;
431 aRec
[7] = (iVal
) & 0xFF;
435 ** Parse a single table-header from the input. Allocate a new change-group
436 ** object with the results. Return SQLITE_OK if successful, or an error code
439 static int fuzzParseHeader(
440 FuzzChangeset
*pParse
, /* Changeset parse object */
441 u8
**ppHdr
, /* IN/OUT: Iterator */
442 u8
*pEnd
, /* 1 byte past EOF */
443 FuzzChangesetGroup
**ppGrp
/* OUT: New change-group object */
446 FuzzChangesetGroup
*pGrp
;
447 u8 cHdr
= (pParse
->bPatchset
? 'P' : 'T');
449 assert( pEnd
>(*ppHdr
) );
450 pGrp
= (FuzzChangesetGroup
*)fuzzMalloc(sizeof(FuzzChangesetGroup
));
459 p
+= fuzzGetVarint(p
, &pGrp
->nCol
);
462 pGrp
->zTab
= (const char*)p
;
463 p
= &p
[strlen((const char*)p
)+1];
482 ** Argument p points to a buffer containing a single changeset-record value.
483 ** This function attempts to determine the size of the value in bytes. If
484 ** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the
485 ** buffer does not contain a valid value, SQLITE_CORRUPT is returned and
486 ** the final value of (*pSz) is undefined.
488 static int fuzzChangeSize(u8
*p
, int *pSz
){
491 case 0x00: /* undefined */
492 case 0x05: /* null */
496 case 0x01: /* integer */
497 case 0x02: /* real */
501 case 0x03: /* text */
502 case 0x04: { /* blob */
505 sz
= fuzzGetVarint(&p
[1], &nTxt
);
506 *pSz
= 1 + sz
+ nTxt
;
511 return fuzzCorrupt();
517 ** When this function is called, (*ppRec) points to the start of a
518 ** record in a changeset being parsed. This function adds entries
519 ** to the pParse->apVal[] array for all values and advances (*ppRec)
520 ** to one byte past the end of the record. Argument pEnd points to
521 ** one byte past the end of the input changeset.
523 ** Argument bPkOnly is true if the record being parsed is part of
524 ** a DELETE record in a patchset. In this case, all non-primary-key
525 ** fields have been omitted from the record.
527 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
529 static int fuzzParseRecord(
530 u8
**ppRec
, /* IN/OUT: Iterator */
531 u8
*pEnd
, /* One byte after end of input data */
532 FuzzChangeset
*pParse
, /* Changeset parse context */
533 int bPkOnly
/* True if non-PK fields omitted */
536 FuzzChangesetGroup
*pGrp
= pParse
->apGroup
[pParse
->nGroup
-1];
540 for(i
=0; rc
==SQLITE_OK
&& i
<pGrp
->nCol
; i
++){
541 if( bPkOnly
==0 || pGrp
->aPK
[i
] ){
544 if( (pParse
->nVal
& (pParse
->nVal
-1))==0 ){
545 int nNew
= pParse
->nVal
? pParse
->nVal
*2 : 4;
546 u8
**apNew
= (u8
**)sqlite3_realloc(pParse
->apVal
, nNew
*sizeof(u8
*));
547 if( apNew
==0 ) return SQLITE_NOMEM
;
548 pParse
->apVal
= apNew
;
550 pParse
->apVal
[pParse
->nVal
++] = p
;
551 rc
= fuzzChangeSize(p
, &sz
);
556 if( rc
==SQLITE_OK
&& i
<pGrp
->nCol
){
565 ** Parse the array of changes starting at (*ppData) and add entries for
566 ** all values to the pParse->apVal[] array. Argument pEnd points to one byte
567 ** past the end of the input changeset. If successful, set (*ppData) to point
568 ** to one byte past the end of the change array and return SQLITE_OK.
569 ** Otherwise, return an SQLite error code. The final value of (*ppData) is
570 ** undefined in this case.
572 static int fuzzParseChanges(u8
**ppData
, u8
*pEnd
, FuzzChangeset
*pParse
){
573 u8 cHdr
= (pParse
->bPatchset
? 'P' : 'T');
574 FuzzChangesetGroup
*pGrp
= pParse
->apGroup
[pParse
->nGroup
-1];
579 while( rc
==SQLITE_OK
&& p
<pEnd
&& p
[0]!=cHdr
){
584 if( eOp
==SQLITE_UPDATE
){
586 if( pParse
->bPatchset
==0 ){
587 rc
= fuzzParseRecord(&p
, pEnd
, pParse
, 0);
589 }else if( eOp
!=SQLITE_INSERT
&& eOp
!=SQLITE_DELETE
){
593 int bPkOnly
= (eOp
==SQLITE_DELETE
&& pParse
->bPatchset
);
594 rc
= fuzzParseRecord(&p
, pEnd
, pParse
, bPkOnly
);
599 pGrp
->szChange
= p
- pGrp
->aChange
;
606 ** Parse the changeset stored in buffer pChangeset (nChangeset bytes in
607 ** size). If successful, write the results into (*pParse) and return
608 ** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The
609 ** final state of (*pParse) is undefined in this case.
611 static int fuzzParseChangeset(
612 u8
*pChangeset
, /* Buffer containing changeset */
613 int nChangeset
, /* Size of buffer in bytes */
614 FuzzChangeset
*pParse
/* OUT: Results of parse */
616 u8
*pEnd
= &pChangeset
[nChangeset
];
620 memset(pParse
, 0, sizeof(FuzzChangeset
));
622 pParse
->bPatchset
= (pChangeset
[0]=='P');
625 while( rc
==SQLITE_OK
&& p
<pEnd
){
626 FuzzChangesetGroup
*pGrp
= 0;
628 /* Read a table-header from the changeset */
629 rc
= fuzzParseHeader(pParse
, &p
, pEnd
, &pGrp
);
630 assert( (rc
==SQLITE_OK
)==(pGrp
!=0) );
632 /* If the table-header was successfully parsed, add the new change-group
633 ** to the array and parse the associated changes. */
635 FuzzChangesetGroup
**apNew
= (FuzzChangesetGroup
**)sqlite3_realloc64(
636 pParse
->apGroup
, sizeof(FuzzChangesetGroup
*)*(pParse
->nGroup
+1)
641 apNew
[pParse
->nGroup
] = pGrp
;
642 pParse
->apGroup
= apNew
;
645 rc
= fuzzParseChanges(&p
, pEnd
, pParse
);
653 ** When this function is called, (*ppRec) points to the first byte of
654 ** a record that is part of change-group pGrp. This function attempts
655 ** to output a human-readable version of the record to stdout and advance
656 ** (*ppRec) to point to the first byte past the end of the record before
657 ** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite
660 ** If parameter bPkOnly is non-zero, then all non-primary-key fields have
661 ** been omitted from the record. This occurs for records that are part
662 ** of DELETE changes in patchsets.
664 static int fuzzPrintRecord(FuzzChangesetGroup
*pGrp
, u8
**ppRec
, int bPKOnly
){
668 const char *zPre
= " (";
670 for(i
=0; i
<pGrp
->nCol
; i
++){
671 if( bPKOnly
==0 || pGrp
->aPK
[i
] ){
674 case 0x00: /* undefined */
675 printf("%sn/a", zPre
);
678 case 0x01: { /* integer */
679 sqlite3_int64 iVal
= 0;
680 iVal
= fuzzGetI64(p
);
681 printf("%s%lld", zPre
, iVal
);
686 case 0x02: { /* real */
687 sqlite3_int64 iVal
= 0;
689 iVal
= fuzzGetI64(p
);
690 memcpy(&fVal
, &iVal
, 8);
691 printf("%s%f", zPre
, fVal
);
696 case 0x03: /* text */
697 case 0x04: { /* blob */
699 p
+= fuzzGetVarint(p
, &nTxt
);
700 printf("%s%s", zPre
, eType
==0x03 ? "'" : "X'");
701 for(i
=0; i
<nTxt
; i
++){
705 char aHex
[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
706 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
708 printf("%c", aHex
[ p
[i
]>>4 ]);
709 printf("%c", aHex
[ p
[i
] & 0x0F ]);
717 case 0x05: /* null */
718 printf("%sNULL", zPre
);
731 ** Print a human-readable version of the table-header and all changes in the
732 ** change-group passed as the second argument.
734 static void fuzzPrintGroup(FuzzChangeset
*pParse
, FuzzChangesetGroup
*pGrp
){
738 /* The table header */
739 printf("TABLE: %s nCol=%d aPK=", pGrp
->zTab
, pGrp
->nCol
);
740 for(i
=0; i
<pGrp
->nCol
; i
++){
741 printf("%d", (int)pGrp
->aPK
[i
]);
745 /* The array of changes */
747 for(i
=0; i
<pGrp
->nChange
; i
++){
750 printf("%s (ind=%d):",
751 (eType
==SQLITE_INSERT
) ? "INSERT" :
752 (eType
==SQLITE_DELETE
? "DELETE" : "UPDATE"),
757 if( pParse
->bPatchset
==0 && eType
==SQLITE_UPDATE
){
758 fuzzPrintRecord(pGrp
, &p
, 0);
760 fuzzPrintRecord(pGrp
, &p
, eType
==SQLITE_DELETE
&& pParse
->bPatchset
);
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.
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.
775 static int fuzzSelectChange(FuzzChangeset
*pParse
, FuzzChange
*pChange
){
778 memset(pChange
, 0, sizeof(FuzzChange
));
779 pChange
->eType
= fuzzRandomInt(FUZZ_COLUMN_DEL
) + 1;
781 assert( pChange
->eType
==FUZZ_VALUE_SUB
782 || pChange
->eType
==FUZZ_VALUE_MOD
783 || pChange
->eType
==FUZZ_VALUE_RND
784 || pChange
->eType
==FUZZ_CHANGE_DUP
785 || pChange
->eType
==FUZZ_CHANGE_DEL
786 || pChange
->eType
==FUZZ_CHANGE_TYPE
787 || pChange
->eType
==FUZZ_CHANGE_FIELD
788 || pChange
->eType
==FUZZ_CHANGE_INDIRECT
789 || pChange
->eType
==FUZZ_GROUP_DUP
790 || pChange
->eType
==FUZZ_GROUP_DEL
791 || pChange
->eType
==FUZZ_GROUP_SWAP
792 || pChange
->eType
==FUZZ_COLUMN_ADD
793 || pChange
->eType
==FUZZ_COLUMN_ADDPK
794 || pChange
->eType
==FUZZ_COLUMN_DEL
797 pChange
->iGroup
= fuzzRandomInt(pParse
->nGroup
);
798 pChange
->iChange
= fuzzRandomInt(pParse
->nChange
);
799 if( pChange
->eType
==FUZZ_CHANGE_FIELD
){
800 if( pParse
->nUpdate
==0 ) return -1;
801 pChange
->iChange
= fuzzRandomInt(pParse
->nUpdate
);
804 pChange
->iDelete
= -1;
805 if( pChange
->eType
==FUZZ_COLUMN_DEL
){
806 FuzzChangesetGroup
*pGrp
= pParse
->apGroup
[pChange
->iGroup
];
808 pChange
->iDelete
= fuzzRandomInt(pGrp
->nCol
);
809 for(i
=pGrp
->nCol
-1; i
>=0; i
--){
810 if( pGrp
->aPK
[i
] && pChange
->iDelete
!=i
) break;
815 if( pChange
->eType
==FUZZ_GROUP_SWAP
){
816 FuzzChangesetGroup
*pGrp
;
817 int iGrp
= pChange
->iGroup
;
818 if( pParse
->nGroup
==1 ) return -1;
819 while( iGrp
==pChange
->iGroup
){
820 iGrp
= fuzzRandomInt(pParse
->nGroup
);
822 pGrp
= pParse
->apGroup
[pChange
->iGroup
];
823 pParse
->apGroup
[pChange
->iGroup
] = pParse
->apGroup
[iGrp
];
824 pParse
->apGroup
[iGrp
] = pGrp
;
827 if( pChange
->eType
==FUZZ_VALUE_SUB
828 || pChange
->eType
==FUZZ_VALUE_MOD
829 || pChange
->eType
==FUZZ_VALUE_RND
831 iSub
= fuzzRandomInt(pParse
->nVal
);
832 pChange
->pSub1
= pParse
->apVal
[iSub
];
833 if( pChange
->eType
==FUZZ_VALUE_SUB
){
834 iSub
= fuzzRandomInt(pParse
->nVal
);
835 pChange
->pSub2
= pParse
->apVal
[iSub
];
837 pChange
->pSub2
= pChange
->aSub
;
840 if( pChange
->eType
==FUZZ_VALUE_RND
){
841 pChange
->aSub
[0] = (u8
)(fuzzRandomInt(5) + 1);
842 switch( pChange
->aSub
[0] ){
843 case 0x01: { /* integer */
844 u64 iVal
= fuzzRandomU64();
845 fuzzPutU64(&pChange
->aSub
[1], iVal
);
849 case 0x02: { /* real */
850 u64 iVal1
= fuzzRandomU64();
851 u64 iVal2
= fuzzRandomU64();
852 double d
= (double)iVal1
/ (double)iVal2
;
853 memcpy(&iVal1
, &d
, sizeof(iVal1
));
854 fuzzPutU64(&pChange
->aSub
[1], iVal1
);
858 case 0x03: /* text */
859 case 0x04: { /* blob */
860 int nByte
= fuzzRandomInt(48);
861 pChange
->aSub
[1] = (u8
)nByte
;
862 fuzzRandomBlob(nByte
, &pChange
->aSub
[2]);
863 if( pChange
->aSub
[0]==0x03 ){
865 for(i
=0; i
<nByte
; i
++){
866 pChange
->aSub
[2+i
] &= 0x7F;
873 if( pChange
->eType
==FUZZ_VALUE_MOD
){
876 fuzzChangeSize(pChange
->pSub1
, &sz
);
877 memcpy(pChange
->aSub
, pChange
->pSub1
, sz
);
878 switch( pChange
->aSub
[0] ){
881 iMod
= fuzzRandomInt(8) + 1;
884 case 0x03: /* text */
885 case 0x04: { /* blob */
887 int iFirst
= 1 + fuzzGetVarint(&pChange
->aSub
[1], &nByte
);
889 iMod
= fuzzRandomInt(nByte
) + iFirst
;
896 u8 mask
= (1 << fuzzRandomInt(8 - (pChange
->aSub
[0]==0x03)));
897 pChange
->aSub
[iMod
] ^= mask
;
906 ** Copy a single change from the input to the output changeset, making
907 ** any modifications specified by (*pFuzz).
909 static int fuzzCopyChange(
910 FuzzChangeset
*pParse
,
913 u8
**pp
, u8
**ppOut
/* IN/OUT: Input and output pointers */
915 int bPS
= pParse
->bPatchset
;
916 FuzzChangesetGroup
*pGrp
= pParse
->apGroup
[iGrp
];
921 int nRec
= ((eType
==SQLITE_UPDATE
&& !bPS
) ? 2 : 1);
926 if( pFuzz
->iCurrent
==pFuzz
->iChange
&& pFuzz
->eType
==FUZZ_CHANGE_TYPE
){
929 eNew
= SQLITE_DELETE
;
932 eNew
= SQLITE_UPDATE
;
935 eNew
= SQLITE_INSERT
;
940 if( pFuzz
->iCurrent
==pFuzz
->iChange
941 && pFuzz
->eType
==FUZZ_CHANGE_FIELD
&& eType
==SQLITE_UPDATE
947 for(i
=0; i
<pGrp
->nCol
; i
++){
948 if( pCsr
[0] && pGrp
->aPK
[i
]==0 ) nDef
++;
949 fuzzChangeSize(pCsr
, &sz
);
952 if( nDef
<=1 ) return -1;
953 nDef
= fuzzRandomInt(nDef
);
955 for(i
=0; i
<pGrp
->nCol
; i
++){
956 if( pCsr
[0] && pGrp
->aPK
[i
]==0 ){
957 if( nDef
==0 ) iUndef
= i
;
960 fuzzChangeSize(pCsr
, &sz
);
965 /* Copy the change type and indirect flag. If the fuzz mode is
966 ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for
967 ** fuzzing, invert the indirect flag. */
969 if( pFuzz
->eType
==FUZZ_CHANGE_INDIRECT
&& pFuzz
->iCurrent
==pFuzz
->iChange
){
970 *(pOut
++) = !(*(p
++));
975 for(iRec
=0; iRec
<nRec
; iRec
++){
978 /* Copy the next record from the output to the input.
980 for(i
=0; i
<pGrp
->nCol
; i
++){
984 /* If this is a patchset, and the input is a DELETE, then the only
985 ** fields present are the PK fields. So, if this is not a PK, skip to
986 ** the next column. If the current fuzz is FUZZ_CHANGE_TYPE, then
987 ** write a randomly selected value to the output. */
988 if( bPS
&& eType
==SQLITE_DELETE
&& pGrp
->aPK
[i
]==0 ){
990 assert( eNew
==SQLITE_UPDATE
);
992 pCopy
= pParse
->apVal
[fuzzRandomInt(pParse
->nVal
)];
993 }while( pCopy
[0]==0x00 );
994 fuzzChangeSize(pCopy
, &sz
);
995 memcpy(pOut
, pCopy
, sz
);
1001 if( p
==pFuzz
->pSub1
){
1002 pCopy
= pFuzz
->pSub2
;
1003 }else if( p
==pFuzz
->pSub2
){
1004 pCopy
= pFuzz
->pSub1
;
1005 }else if( i
==iUndef
){
1009 if( pCopy
[0]==0x00 && eNew
!=eType
&& eType
==SQLITE_UPDATE
&& iRec
==0 ){
1010 while( pCopy
[0]==0x00 ){
1011 pCopy
= pParse
->apVal
[fuzzRandomInt(pParse
->nVal
)];
1013 }else if( p
[0]==0x00 && pCopy
[0]!=0x00 ){
1016 if( pGrp
->aPK
[i
]>0 && pCopy
[0]==0x05 ) return -1;
1019 if( (pFuzz
->iGroup
!=iGrp
|| i
!=pFuzz
->iDelete
)
1020 && (eNew
==eType
|| eType
!=SQLITE_UPDATE
|| iRec
==0)
1021 && (eNew
==eType
|| eNew
!=SQLITE_DELETE
|| !bPS
|| pGrp
->aPK
[i
])
1023 fuzzChangeSize(pCopy
, &sz
);
1024 memcpy(pOut
, pCopy
, sz
);
1026 nUpdate
+= (pGrp
->aPK
[i
]==0 && pCopy
[0]!=0x00);
1029 fuzzChangeSize(p
, &sz
);
1033 if( iGrp
==pFuzz
->iGroup
){
1034 if( pFuzz
->eType
==FUZZ_COLUMN_ADD
){
1035 if( !bPS
|| eType
!=SQLITE_DELETE
) *(pOut
++) = 0x05;
1036 }else if( pFuzz
->eType
==FUZZ_COLUMN_ADDPK
){
1043 pNew
= pParse
->apVal
[fuzzRandomInt(pParse
->nVal
)];
1044 }while( pNew
[0]==0x00 || pNew
[0]==0x05 );
1045 fuzzChangeSize(pNew
, &szNew
);
1046 memcpy(pOut
, pNew
, szNew
);
1053 if( pFuzz
->iCurrent
==pFuzz
->iChange
){
1054 if( pFuzz
->eType
==FUZZ_CHANGE_DUP
){
1055 int nByte
= pOut
- (*ppOut
);
1056 memcpy(pOut
, *ppOut
, nByte
);
1060 if( pFuzz
->eType
==FUZZ_CHANGE_DEL
){
1063 if( eNew
!=eType
&& eNew
==SQLITE_UPDATE
&& !bPS
){
1065 u8
*pCsr
= (*ppOut
) + 2;
1066 for(i
=0; i
<pGrp
->nCol
; i
++){
1069 if( pGrp
->aPK
[i
] ) pCopy
= (u8
*)"\0";
1070 fuzzChangeSize(pCopy
, &sz
);
1071 memcpy(pOut
, pCopy
, sz
);
1073 fuzzChangeSize(pCsr
, &sz
);
1079 /* If a column is being deleted from this group, and this change was an
1080 ** UPDATE, and there are now no non-PK, non-undefined columns in the
1081 ** change, remove it altogether. */
1082 if( pFuzz
->eType
==FUZZ_COLUMN_DEL
&& pFuzz
->iGroup
==iGrp
1083 && eType
==SQLITE_UPDATE
&& nUpdate
==0
1090 pFuzz
->iCurrent
+= (eType
==SQLITE_UPDATE
|| pFuzz
->eType
!=FUZZ_CHANGE_FIELD
);
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.
1099 ** Return SQLITE_OK if successful, or an SQLite error code if an error occurs.
1101 static int fuzzDoOneFuzz(
1102 const char *zOut
, /* Filename to write modified changeset to */
1103 u8
*pBuf
, /* Buffer to use for modified changeset */
1104 FuzzChangeset
*pParse
/* Parse of input changeset */
1112 rc
= fuzzSelectChange(pParse
, &change
);
1113 for(iGrp
=0; rc
==SQLITE_OK
&& iGrp
<pParse
->nGroup
; iGrp
++){
1114 FuzzChangesetGroup
*pGrp
= pParse
->apGroup
[iGrp
];
1115 int nTab
= strlen(pGrp
->zTab
) + 1;
1119 /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to
1120 ** the next group. Unless this is the only group in the changeset - in
1121 ** that case this change cannot be applied.
1123 ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two
1124 ** copies of the group. */
1125 if( change
.iGroup
==iGrp
){
1126 if( change
.eType
==FUZZ_GROUP_DEL
){
1127 if( pParse
->nGroup
==1 ) rc
= -1;
1130 else if( change
.eType
==FUZZ_GROUP_DUP
){
1135 for(j
=0; j
<nRep
; j
++){
1138 u8
*p
= pGrp
->aChange
;
1139 int nCol
= pGrp
->nCol
;
1141 if( iGrp
==change
.iGroup
){
1142 if( change
.eType
==FUZZ_COLUMN_ADD
1143 || change
.eType
==FUZZ_COLUMN_ADDPK
1146 }else if( change
.eType
==FUZZ_COLUMN_DEL
){
1148 iPKDel
= pGrp
->aPK
[change
.iDelete
];
1152 /* Output a table header */
1153 pOut
++[0] = pParse
->bPatchset
? 'P' : 'T';
1154 pOut
+= fuzzPutVarint(pOut
, nCol
);
1156 for(i
=0; i
<pGrp
->nCol
; i
++){
1157 if( iGrp
!=change
.iGroup
|| i
!=change
.iDelete
){
1158 u8 v
= pGrp
->aPK
[i
];
1159 if( iPKDel
&& v
>iPKDel
) v
--;
1163 if( nCol
>pGrp
->nCol
){
1164 if( change
.eType
==FUZZ_COLUMN_ADD
){
1168 for(i
=0; i
<pGrp
->nCol
; i
++){
1169 if( pGrp
->aPK
[i
]>max
) max
= pGrp
->aPK
[i
];
1174 memcpy(pOut
, pGrp
->zTab
, nTab
);
1177 /* Output the change array. */
1179 for(i
=0; rc
==SQLITE_OK
&& i
<pGrp
->nChange
; i
++){
1180 rc
= fuzzCopyChange(pParse
, iGrp
, &change
, &p
, &pOut
);
1182 if( pOut
==pSaved
) rc
= -1;
1185 if( rc
==SQLITE_OK
){
1186 fuzzWriteFile(zOut
, pBuf
, pOut
-pBuf
);
1193 int main(int argc
, char **argv
){
1194 int nRepeat
= 0; /* Number of output files */
1195 int iSeed
= 0; /* Value of PRNG seed */
1196 const char *zInput
; /* Name of input file */
1197 void *pChangeset
= 0; /* Input changeset */
1198 int nChangeset
= 0; /* Size of input changeset in bytes */
1199 int i
; /* Current output file */
1200 FuzzChangeset changeset
; /* Partially parsed changeset */
1204 if( argc
!=4 && argc
!=2 ) usage(argv
[0]);
1207 fuzzReadFile(zInput
, &nChangeset
, &pChangeset
);
1208 rc
= fuzzParseChangeset(pChangeset
, nChangeset
, &changeset
);
1210 if( rc
==SQLITE_OK
){
1212 for(i
=0; i
<changeset
.nGroup
; i
++){
1213 fuzzPrintGroup(&changeset
, changeset
.apGroup
[i
]);
1216 pBuf
= (u8
*)fuzzMalloc((sqlite3_int64
)nChangeset
*2 + 1024);
1220 iSeed
= atoi(argv
[2]);
1221 nRepeat
= atoi(argv
[3]);
1222 fuzzRandomSeed((unsigned int)iSeed
);
1223 for(i
=0; rc
==SQLITE_OK
&& i
<nRepeat
; i
++){
1224 char *zOut
= sqlite3_mprintf("%s-%d", zInput
, i
);
1225 rc
= fuzzDoOneFuzz(zOut
, pBuf
, &changeset
);
1233 if( rc
!=SQLITE_OK
){
1234 fprintf(stderr
, "error while processing changeset: %d\n", rc
);