xref: /sqlite-3.40.0/ext/session/changesetfuzz.c (revision f095a1af)
1 /*
2 ** 2018-11-01
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
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.
10 **
11 *************************************************************************
12 ** This file contains code to implement the "changesetfuzz" command
13 ** line utility for fuzzing changeset blobs without corrupting them.
14 */
15 
16 
17 /************************************************************************
18 ** USAGE:
19 **
20 ** This program may be invoked in two ways:
21 **
22 **   changesetfuzz INPUT
23 **   changesetfuzz INPUT SEED N
24 **
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.
28 **
29 ** In the second form, arguments SEED and N must both be integers. In this
30 ** case, this program writes N binary changesets to disk. Each output
31 ** changeset is a slightly modified - "fuzzed" - version of the input.
32 ** The output changesets are written to files name "INPUT-$n", where $n is
33 ** an integer between 0 and N-1, inclusive. Output changesets are always
34 ** well-formed. Parameter SEED is used to seed the PRNG - any two
35 ** invocations of this program with the same SEED and input changeset create
36 ** the same N output changesets.
37 **
38 ** The ways in which an input changeset may be fuzzed are as follows:
39 **
40 **   1. Any two values within the changeset may be exchanged.
41 **
42 **   2. Any TEXT, BLOB, INTEGER or REAL value within the changeset
43 **      may have a single bit of its content flipped.
44 **
45 **   3. Any value within a changeset may be replaced by a pseudo-randomly
46 **      generated value.
47 **
48 ** The above operations never set a PRIMARY KEY column to NULL. Nor do they
49 ** set any value to "undefined", or replace any "undefined" value with
50 ** another. Any such operation risks producing a changeset that is not
51 ** well-formed.
52 **
53 **   4. A single change may be duplicated.
54 **
55 **   5. A single change may be removed, so long as this does not mean that
56 **      there are zero changes following a table-header within the changeset.
57 **
58 **   6. A single change may have its type (INSERT, DELETE, UPDATE) changed.
59 **      If an INSERT is changed to a DELETE (or vice versa), the type is
60 **      simply changed - no other modifications are required. If an INSERT
61 **      or DELETE is changed to an UPDATE, then the single record is duplicated
62 **      (as both the old.* and new.* records of the new UPDATE change). If an
63 **      UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
64 **      and any "undefined" fields replaced with pseudo-randomly generated
65 **      values.
66 **
67 **   7. An UPDATE change that modifies N table columns may be modified so
68 **      that it updates N-1 columns, so long as (N>1).
69 **
70 */
71 
72 #include "sqlite3.h"
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <assert.h>
77 #include <ctype.h>
78 
79 #define FUZZ_VALUE_SUB     1      /* Replace one value with a copy of another */
80 #define FUZZ_VALUE_MOD     2      /* Modify content by 1 bit */
81 #define FUZZ_VALUE_RND     3      /* Replace with pseudo-random value */
82 
83 #define FUZZ_CHANGE_DUP    4
84 #define FUZZ_CHANGE_DEL    5
85 #define FUZZ_CHANGE_TYPE   6
86 #define FUZZ_CHANGE_FIELD  7
87 
88 #if 0
89 #define FUZZ_COLUMN_ADD    1      /* Add column to table definition */
90 #define FUZZ_COLUMN_DEL    2      /* Remove column from table definition */
91 #define FUZZ_PK_ADD        3      /* Add a PK column */
92 #define FUZZ_PK_DEL        4      /* Delete a PK column */
93 #define FUZZ_NAME_CHANGE   5      /* Change a table name */
94 #endif
95 
96 
97 
98 typedef unsigned char u8;
99 typedef sqlite3_uint64 u64;
100 typedef sqlite3_int64 i64;
101 typedef unsigned int u32;
102 
103 /*
104 ** Show a usage message on stderr then quit.
105 */
106 static void usage(const char *argv0){
107   fprintf(stderr, "Usage: %s FILENAME ?SEED N?\n", argv0);
108   exit(1);
109 }
110 
111 /*
112 ** Read the content of a disk file into an in-memory buffer
113 */
114 static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
115   FILE *f;
116   int sz;
117   void *pBuf;
118   f = fopen(zFilename, "rb");
119   if( f==0 ){
120     fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
121     exit(1);
122   }
123   fseek(f, 0, SEEK_END);
124   sz = (int)ftell(f);
125   rewind(f);
126   pBuf = sqlite3_malloc( sz ? sz : 1 );
127   if( pBuf==0 ){
128     fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
129             sz, zFilename);
130     exit(1);
131   }
132   if( sz>0 ){
133     if( fread(pBuf, sz, 1, f)!=1 ){
134       fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", sz, zFilename);
135       exit(1);
136     }
137     fclose(f);
138   }
139   *pSz = sz;
140   *ppBuf = pBuf;
141 }
142 
143 static void fuzzWriteFile(const char *zFilename, void *pBuf, int nBuf){
144   FILE *f;
145   f = fopen(zFilename, "wb");
146   if( f==0 ){
147     fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename);
148     exit(1);
149   }
150   if( fwrite(pBuf, nBuf, 1, f)!=1 ){
151     fprintf(stderr, "cannot write to \"%s\"\n", zFilename);
152     exit(1);
153   }
154   fclose(f);
155 }
156 
157 static int fuzzCorrupt(){
158   return SQLITE_CORRUPT;
159 }
160 
161 /*************************************************************************
162 ** The following block is a copy of the implementation of SQLite function
163 ** sqlite3_randomness. This version has two important differences:
164 **
165 **   1. It always uses the same seed. So the sequence of random data output
166 **      is the same for every run of the program.
167 **
168 **   2. It is not threadsafe.
169 */
170 static struct sqlite3PrngType {
171   unsigned char i, j;             /* State variables */
172   unsigned char s[256];           /* State variables */
173 } sqlite3Prng = {
174     0xAF, 0x28,
175   {
176     0x71, 0xF5, 0xB4, 0x6E, 0x80, 0xAB, 0x1D, 0xB8,
177     0xFB, 0xB7, 0x49, 0xBF, 0xFF, 0x72, 0x2D, 0x14,
178     0x79, 0x09, 0xE3, 0x78, 0x76, 0xB0, 0x2C, 0x0A,
179     0x8E, 0x23, 0xEE, 0xDF, 0xE0, 0x9A, 0x2F, 0x67,
180     0xE1, 0xBE, 0x0E, 0xA7, 0x08, 0x97, 0xEB, 0x77,
181     0x78, 0xBA, 0x9D, 0xCA, 0x49, 0x4C, 0x60, 0x9A,
182     0xF6, 0xBD, 0xDA, 0x7F, 0xBC, 0x48, 0x58, 0x52,
183     0xE5, 0xCD, 0x83, 0x72, 0x23, 0x52, 0xFF, 0x6D,
184     0xEF, 0x0F, 0x82, 0x29, 0xA0, 0x83, 0x3F, 0x7D,
185     0xA4, 0x88, 0x31, 0xE7, 0x88, 0x92, 0x3B, 0x9B,
186     0x3B, 0x2C, 0xC2, 0x4C, 0x71, 0xA2, 0xB0, 0xEA,
187     0x36, 0xD0, 0x00, 0xF1, 0xD3, 0x39, 0x17, 0x5D,
188     0x2A, 0x7A, 0xE4, 0xAD, 0xE1, 0x64, 0xCE, 0x0F,
189     0x9C, 0xD9, 0xF5, 0xED, 0xB0, 0x22, 0x5E, 0x62,
190     0x97, 0x02, 0xA3, 0x8C, 0x67, 0x80, 0xFC, 0x88,
191     0x14, 0x0B, 0x15, 0x10, 0x0F, 0xC7, 0x40, 0xD4,
192     0xF1, 0xF9, 0x0E, 0x1A, 0xCE, 0xB9, 0x1E, 0xA1,
193     0x72, 0x8E, 0xD7, 0x78, 0x39, 0xCD, 0xF4, 0x5D,
194     0x2A, 0x59, 0x26, 0x34, 0xF2, 0x73, 0x0B, 0xA0,
195     0x02, 0x51, 0x2C, 0x03, 0xA3, 0xA7, 0x43, 0x13,
196     0xE8, 0x98, 0x2B, 0xD2, 0x53, 0xF8, 0xEE, 0x91,
197     0x7D, 0xE7, 0xE3, 0xDA, 0xD5, 0xBB, 0xC0, 0x92,
198     0x9D, 0x98, 0x01, 0x2C, 0xF9, 0xB9, 0xA0, 0xEB,
199     0xCF, 0x32, 0xFA, 0x01, 0x49, 0xA5, 0x1D, 0x9A,
200     0x76, 0x86, 0x3F, 0x40, 0xD4, 0x89, 0x8F, 0x9C,
201     0xE2, 0xE3, 0x11, 0x31, 0x37, 0xB2, 0x49, 0x28,
202     0x35, 0xC0, 0x99, 0xB6, 0xD0, 0xBC, 0x66, 0x35,
203     0xF7, 0x83, 0x5B, 0xD7, 0x37, 0x1A, 0x2B, 0x18,
204     0xA6, 0xFF, 0x8D, 0x7C, 0x81, 0xA8, 0xFC, 0x9E,
205     0xC4, 0xEC, 0x80, 0xD0, 0x98, 0xA7, 0x76, 0xCC,
206     0x9C, 0x2F, 0x7B, 0xFF, 0x8E, 0x0E, 0xBB, 0x90,
207     0xAE, 0x13, 0x06, 0xF5, 0x1C, 0x4E, 0x52, 0xF7
208   }
209 };
210 
211 /*
212 ** Generate and return single random byte
213 */
214 static unsigned char fuzzRandomByte(void){
215   unsigned char t;
216   sqlite3Prng.i++;
217   t = sqlite3Prng.s[sqlite3Prng.i];
218   sqlite3Prng.j += t;
219   sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
220   sqlite3Prng.s[sqlite3Prng.j] = t;
221   t += sqlite3Prng.s[sqlite3Prng.i];
222   return sqlite3Prng.s[t];
223 }
224 
225 /*
226 ** Return N random bytes.
227 */
228 static void fuzzRandomBlob(int nBuf, unsigned char *zBuf){
229   int i;
230   for(i=0; i<nBuf; i++){
231     zBuf[i] = fuzzRandomByte();
232   }
233 }
234 
235 /*
236 ** Return a random integer between 0 and nRange (not inclusive).
237 */
238 static unsigned int fuzzRandomInt(unsigned int nRange){
239   unsigned int ret;
240   assert( nRange>0 );
241   fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
242   return (ret % nRange);
243 }
244 
245 static u64 fuzzRandomU64(){
246   u64 ret;
247   fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
248   return ret;
249 }
250 
251 static void fuzzRandomSeed(unsigned int iSeed){
252   int i;
253   for(i=0; i<256; i+=4){
254     sqlite3Prng.s[i] ^= ((iSeed >> 24) & 0xFF);
255     sqlite3Prng.s[i+1] ^= ((iSeed >> 16) & 0xFF);
256     sqlite3Prng.s[i+2] ^= ((iSeed >>  8) & 0xFF);
257     sqlite3Prng.s[i+3] ^= ((iSeed >>  0) & 0xFF);
258   }
259 }
260 
261 /*
262 ** End of code for generating pseudo-random values.
263 *************************************************************************/
264 
265 typedef struct FuzzChangeset FuzzChangeset;
266 typedef struct FuzzChangesetGroup FuzzChangesetGroup;
267 typedef struct FuzzChange FuzzChange;
268 
269 #define FUZZER_AVAL_SZ 512
270 
271 /*
272 ** Object containing partially parsed changeset.
273 */
274 struct FuzzChangeset {
275   FuzzChangesetGroup **apGroup;   /* Array of groups in changeset */
276   int nGroup;                     /* Number of items in list pGroup */
277   u8 *aVal[FUZZER_AVAL_SZ];       /* Array of first few values in changeset */
278   int nVal;                       /* Number of used slots in aVal[] */
279   int nChange;                    /* Number of changes in changeset */
280   int nUpdate;                    /* Number of UPDATE changes in changeset */
281 };
282 
283 struct FuzzChangesetGroup {
284   const char *zTab;               /* Name of table */
285   int nCol;                       /* Number of columns in table */
286   u8 *aPK;                        /* PK array for this table */
287   u8 *aChange;                    /* Buffer containing array of changes */
288   int szChange;                   /* Size of buffer aChange[] in bytes */
289   int nChange;                    /* Number of changes in buffer aChange[] */
290   FuzzChangesetGroup *pNextGroup;
291 };
292 
293 /*
294 ** Description of a fuzz change to be applied to a changeset.
295 */
296 struct FuzzChange {
297   int eType;                      /* One of the FUZZ_* constants above */
298   int iChange;                    /* Change to modify */
299   u8 *pSub1;
300   u8 *pSub2;
301   u8 aSub[128];                   /* Substitute value */
302 
303   int iCurrent;                   /* Current change number */
304 };
305 
306 static void *fuzzMalloc(int nByte){
307   void *pRet = sqlite3_malloc(nByte);
308   if( pRet ){
309     memset(pRet, 0, nByte);
310   }
311   return pRet;
312 }
313 
314 static void fuzzFree(void *p){
315   sqlite3_free(p);
316 }
317 
318 static int fuzzGetVarint(u8 *p, int *pnVal){
319   int i;
320   sqlite3_uint64 nVal = 0;
321   for(i=0; i<9; i++){
322     nVal = (nVal<<7) + (p[i] & 0x7F);
323     if( (p[i] & 0x80)==0 ){
324       i++;
325       break;
326     }
327   }
328   *pnVal = (int)nVal;
329   return i;
330 }
331 
332 static int fuzzPutVarint(u8 *p, int nVal){
333   assert( nVal>0 && nVal<2097152 );
334   if( nVal<128 ){
335     p[0] = nVal;
336     return 1;
337   }
338   if( nVal<16384 ){
339     p[0] = ((nVal >> 7) & 0x7F) | 0x80;
340     p[1] = (nVal & 0x7F);
341     return 2;
342   }
343 
344   p[0] = ((nVal >> 14) & 0x7F) | 0x80;
345   p[1] = ((nVal >> 7) & 0x7F) | 0x80;
346   p[2] = (nVal & 0x7F);
347   return 3;
348 }
349 
350 /* Load an unaligned and unsigned 32-bit integer */
351 #define FUZZ_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
352 
353 /*
354 ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
355 ** the value read.
356 */
357 static sqlite3_int64 fuzzGetI64(u8 *aRec){
358   u64 x = FUZZ_UINT32(aRec);
359   u32 y = FUZZ_UINT32(aRec+4);
360   x = (x<<32) + y;
361   return (sqlite3_int64)x;
362 }
363 
364 static void fuzzPutU64(u8 *aRec, u64 iVal){
365   aRec[0] = (iVal>>56) & 0xFF;
366   aRec[1] = (iVal>>48) & 0xFF;
367   aRec[2] = (iVal>>40) & 0xFF;
368   aRec[3] = (iVal>>32) & 0xFF;
369   aRec[4] = (iVal>>24) & 0xFF;
370   aRec[5] = (iVal>>16) & 0xFF;
371   aRec[6] = (iVal>> 8) & 0xFF;
372   aRec[7] = (iVal)     & 0xFF;
373 }
374 
375 static int fuzzParseHeader(u8 **ppHdr, u8 *pEnd, FuzzChangesetGroup **ppGrp){
376   int rc = SQLITE_OK;
377   FuzzChangesetGroup *pGrp;
378 
379   assert( pEnd>(*ppHdr) );
380   pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
381   if( !pGrp ){
382     rc = SQLITE_NOMEM;
383   }else{
384     u8 *p = *ppHdr;
385     if( p[0]!='T' ){
386       rc = fuzzCorrupt();
387     }else{
388       p++;
389       p += fuzzGetVarint(p, &pGrp->nCol);
390       pGrp->aPK = p;
391       p += pGrp->nCol;
392       pGrp->zTab = (const char*)p;
393       p = &p[strlen(p)+1];
394 
395       if( p>=pEnd ){
396         rc = fuzzCorrupt();
397       }
398     }
399     *ppHdr = p;
400   }
401 
402   if( rc!=SQLITE_OK ){
403     fuzzFree(pGrp);
404     pGrp = 0;
405   }
406 
407   *ppGrp = pGrp;
408   return rc;
409 }
410 
411 static int fuzzChangeSize(u8 *p, int *pSz){
412   u8 eType = p[0];
413   switch( eType ){
414     case 0x00:                    /* undefined */
415     case 0x05:                    /* null */
416       *pSz = 1;
417       break;
418 
419     case 0x01:                    /* integer */
420     case 0x02:                    /* real */
421       *pSz = 9;
422       break;
423 
424     case 0x03:                    /* text */
425     case 0x04: {                  /* blob */
426       int nTxt;
427       int sz;
428       sz = fuzzGetVarint(&p[1], &nTxt);
429       *pSz = 1 + sz + nTxt;
430       break;
431     }
432 
433     default:
434       return fuzzCorrupt();
435   }
436   return SQLITE_OK;
437 }
438 
439 static int fuzzParseRecord(u8 **ppRec, u8 *pEnd, FuzzChangeset *pParse){
440   int rc = SQLITE_OK;
441   int nCol = pParse->apGroup[pParse->nGroup-1]->nCol;
442   int i;
443   u8 *p = *ppRec;
444 
445   for(i=0; rc==SQLITE_OK && i<nCol && p<pEnd; i++){
446     int sz;
447     if( pParse->nVal<FUZZER_AVAL_SZ ){
448       pParse->aVal[pParse->nVal++] = p;
449     }
450     rc = fuzzChangeSize(p, &sz);
451     p += sz;
452   }
453 
454   if( rc==SQLITE_OK && i<nCol ){
455     rc = fuzzCorrupt();
456   }
457 
458   *ppRec = p;
459   return rc;
460 }
461 
462 static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
463   FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
464   int rc = SQLITE_OK;
465   u8 *p = *ppData;
466 
467   pGrp->aChange = p;
468   while( rc==SQLITE_OK && p<pEnd && p[0]!='T' ){
469     u8 eOp = p[0];
470     u8 bIndirect = p[1];
471 
472     p += 2;
473     if( eOp==SQLITE_UPDATE ){
474       pParse->nUpdate++;
475       rc = fuzzParseRecord(&p, pEnd, pParse);
476     }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
477       rc = fuzzCorrupt();
478     }
479     if( rc==SQLITE_OK ){
480       rc = fuzzParseRecord(&p, pEnd, pParse);
481     }
482     pGrp->nChange++;
483     pParse->nChange++;
484   }
485   pGrp->szChange = p - pGrp->aChange;
486 
487   *ppData = p;
488   return rc;
489 }
490 
491 static int fuzzParseChangeset(
492   u8 *pChangeset,                 /* Buffer containing changeset */
493   int nChangeset,                 /* Size of buffer in bytes */
494   FuzzChangeset *pParse           /* OUT: Results of parse */
495 ){
496   u8 *pEnd = &pChangeset[nChangeset];
497   u8 *p = pChangeset;
498   int rc = SQLITE_OK;
499 
500   memset(pParse, 0, sizeof(FuzzChangeset));
501 
502   while( rc==SQLITE_OK && p<pEnd ){
503     FuzzChangesetGroup *pGrp = 0;
504 
505     /* Read a table-header from the changeset */
506     rc = fuzzParseHeader(&p, pEnd, &pGrp);
507     assert( (rc==SQLITE_OK)==(pGrp!=0) );
508 
509     /* If the table-header was successfully parsed, link the new change-group
510     ** into the linked list and parse the associated array of changes. */
511     if( rc==SQLITE_OK ){
512       FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc(
513           pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
514       );
515       if( apNew==0 ){
516         rc = SQLITE_NOMEM;
517       }else{
518         apNew[pParse->nGroup] = pGrp;
519         pParse->apGroup = apNew;
520         pParse->nGroup++;
521       }
522       rc = fuzzParseChanges(&p, pEnd, pParse);
523     }
524   }
525 
526   return rc;
527 }
528 
529 static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec){
530   int rc = SQLITE_OK;
531   u8 *p = *ppRec;
532   int i;
533   const char *zPre = " (";
534 
535   for(i=0; i<pGrp->nCol; i++){
536     u8 eType = p++[0];
537     switch( eType ){
538       case 0x00:                    /* undefined */
539         printf("%sn/a", zPre);
540         break;
541 
542       case 0x01: {                  /* integer */
543         sqlite3_int64 iVal = 0;
544         iVal = fuzzGetI64(p);
545         printf("%s%lld", zPre, iVal);
546         p += 8;
547         break;
548       }
549 
550       case 0x02: {                  /* real */
551         sqlite3_int64 iVal = 0;
552         double fVal = 0.0;
553         iVal = fuzzGetI64(p);
554         memcpy(&fVal, &iVal, 8);
555         printf("%s%f", zPre, fVal);
556         p += 8;
557         break;
558       }
559 
560       case 0x03:                    /* text */
561       case 0x04: {                  /* blob */
562         int nTxt;
563         int sz;
564         int i;
565         p += fuzzGetVarint(p, &nTxt);
566         printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
567         for(i=0; i<nTxt; i++){
568           if( eType==0x03 ){
569             printf("%c", p[i]);
570           }else{
571             char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
572                              '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
573             };
574             printf("%c", aHex[ p[i]>>4 ]);
575             printf("%c", aHex[ p[i] & 0x0F ]);
576           }
577         }
578         printf("'");
579         p += nTxt;
580         break;
581       }
582 
583       case 0x05:                    /* null */
584         printf("%sNULL", zPre);
585         break;
586     }
587     zPre = ", ";
588   }
589   printf(")");
590 
591   *ppRec = p;
592   return rc;
593 }
594 
595 static int fuzzPrintGroup(FuzzChangesetGroup *pGrp){
596   int i;
597   u8 *p;
598 
599   /* The table header */
600   printf("TABLE:  %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol);
601   for(i=0; i<pGrp->nCol; i++){
602     printf("%d", (int)pGrp->aPK[i]);
603   }
604   printf("\n");
605 
606   /* The array of changes */
607   p = pGrp->aChange;
608   for(i=0; i<pGrp->nChange; i++){
609     u8 eType = p[0];
610     u8 bIndirect = p[1];
611     printf("%s (ind=%d):",
612         (eType==SQLITE_INSERT) ? "INSERT" :
613         (eType==SQLITE_DELETE ? "DELETE" : "UPDATE"),
614         bIndirect
615     );
616     p += 2;
617 
618     if( eType==SQLITE_UPDATE ){
619       fuzzPrintRecord(pGrp, &p);
620     }
621     fuzzPrintRecord(pGrp, &p);
622     printf("\n");
623   }
624 }
625 
626 static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
627   int iSub;
628 
629   memset(pChange, 0, sizeof(FuzzChange));
630   pChange->eType = fuzzRandomInt(7) + FUZZ_VALUE_SUB;
631 
632   assert( pChange->eType==FUZZ_VALUE_SUB
633        || pChange->eType==FUZZ_VALUE_MOD
634        || pChange->eType==FUZZ_VALUE_RND
635        || pChange->eType==FUZZ_CHANGE_DUP
636        || pChange->eType==FUZZ_CHANGE_DEL
637        || pChange->eType==FUZZ_CHANGE_TYPE
638        || pChange->eType==FUZZ_CHANGE_FIELD
639   );
640 
641   pChange->iChange = fuzzRandomInt(pParse->nChange);
642   if( pChange->eType==FUZZ_CHANGE_FIELD ){
643     if( pParse->nUpdate==0 ) return -1;
644     pChange->iChange = fuzzRandomInt(pParse->nUpdate);
645   }
646 
647   if( pChange->eType==FUZZ_VALUE_SUB
648    || pChange->eType==FUZZ_VALUE_MOD
649    || pChange->eType==FUZZ_VALUE_RND
650   ){
651     iSub = fuzzRandomInt(pParse->nVal);
652     pChange->pSub1 = pParse->aVal[iSub];
653     if( pChange->eType==FUZZ_VALUE_SUB ){
654       iSub = fuzzRandomInt(pParse->nVal);
655       pChange->pSub2 = pParse->aVal[iSub];
656     }else{
657       pChange->pSub2 = pChange->aSub;
658     }
659 
660     if( pChange->eType==FUZZ_VALUE_RND ){
661       pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1);
662       switch( pChange->aSub[0] ){
663         case 0x01: {                  /* integer */
664           u64 iVal = fuzzRandomU64();
665           fuzzPutU64(&pChange->aSub[1], iVal);
666           break;
667         }
668 
669         case 0x02: {                  /* real */
670           u64 iVal1 = fuzzRandomU64();
671           u64 iVal2 = fuzzRandomU64();
672           double d = (double)iVal1 / (double)iVal2;
673           memcpy(&iVal1, &d, sizeof(iVal1));
674           fuzzPutU64(&pChange->aSub[1], iVal1);
675           break;
676         }
677 
678         case 0x03:                    /* text */
679         case 0x04: {                  /* blob */
680           int nByte = fuzzRandomInt(48);
681           pChange->aSub[1] = nByte;
682           fuzzRandomBlob(nByte, &pChange->aSub[2]);
683           if( pChange->aSub[0]==0x03 ){
684             int i;
685             for(i=0; i<nByte; i++){
686               pChange->aSub[2+i] &= 0x7F;
687             }
688           }
689           break;
690         }
691       }
692     }
693     if( pChange->eType==FUZZ_VALUE_MOD ){
694       int sz;
695       int iMod = -1;
696       fuzzChangeSize(pChange->pSub1, &sz);
697       memcpy(pChange->aSub, pChange->pSub1, sz);
698       switch( pChange->aSub[0] ){
699         case 0x01:
700         case 0x02:
701           iMod = fuzzRandomInt(8) + 1;
702           break;
703 
704         case 0x03:                    /* text */
705         case 0x04: {                  /* blob */
706           int nByte;
707           int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte);
708           if( nByte>0 ){
709             iMod = fuzzRandomInt(nByte) + iFirst;
710           }
711           break;
712         }
713       }
714 
715       if( iMod>=0 ){
716         u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03)));
717         pChange->aSub[iMod] ^= mask;
718       }
719     }
720   }
721 
722   return SQLITE_OK;
723 }
724 
725 static int fuzzCopyChange(
726   FuzzChangeset *pParse,
727   FuzzChangesetGroup *pGrp,
728   FuzzChange *pFuzz,
729   u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
730 ){
731   u8 *p = *pp;
732   u8 *pOut = *ppOut;
733   u8 eType = p++[0];
734   int iRec;
735   int nRec = (eType==SQLITE_UPDATE ? 2 : 1);
736   int iUndef = -1;
737 
738   u8 eNew = eType;
739   if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
740     switch( eType ){
741       case SQLITE_INSERT:
742         eNew = SQLITE_DELETE;
743         break;
744       case SQLITE_DELETE:
745         eNew = SQLITE_UPDATE;
746         break;
747       case SQLITE_UPDATE:
748         eNew = SQLITE_INSERT;
749         break;
750     }
751   }
752 
753   if( pFuzz->iCurrent==pFuzz->iChange
754    && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE
755   ){
756     int sz;
757     int i;
758     int nDef = 0;
759     u8 *pCsr = p+1;
760     for(i=0; i<pGrp->nCol; i++){
761       if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++;
762       fuzzChangeSize(pCsr, &sz);
763       pCsr += sz;
764     }
765     if( nDef<=1 ) return -1;
766     nDef = fuzzRandomInt(nDef);
767     for(i=0; i<pGrp->nCol; i++){
768       if( pCsr[0] && pGrp->aPK[i]==0 ){
769         if( nDef==0 ) iUndef = i;
770         nDef--;
771       }
772       fuzzChangeSize(pCsr, &sz);
773       pCsr += sz;
774     }
775   }
776 
777   /* Copy the change type and indirect flag */
778   *(pOut++) = eNew;
779   *(pOut++) = *(p++);
780   for(iRec=0; iRec<nRec; iRec++){
781     int i;
782     for(i=0; i<pGrp->nCol; i++){
783       int sz;
784       u8 *pCopy = p;
785 
786       if( p==pFuzz->pSub1 ){
787         pCopy = pFuzz->pSub2;
788       }else if( p==pFuzz->pSub2 ){
789         pCopy = pFuzz->pSub1;
790       }else if( i==iUndef ){
791         pCopy = "\0";
792       }
793 
794       if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
795         while( pCopy[0]==0x00 ){
796           pCopy = pParse->aVal[fuzzRandomInt(pParse->nVal)];
797         }
798       }else if( p[0]==0x00 && pCopy[0]!=0x00 ){
799         return -1;
800       }else{
801         if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
802       }
803 
804       if( eNew==eType || eType!=SQLITE_UPDATE || iRec==0 ){
805         fuzzChangeSize(pCopy, &sz);
806         memcpy(pOut, pCopy, sz);
807         pOut += sz;
808       }
809 
810       fuzzChangeSize(p, &sz);
811       p += sz;
812     }
813   }
814 
815   if( pFuzz->iCurrent==pFuzz->iChange ){
816     if( pFuzz->eType==FUZZ_CHANGE_DUP ){
817       int nByte = pOut - (*ppOut);
818       memcpy(pOut, *ppOut, nByte);
819       pOut += nByte;
820     }
821     if( pFuzz->eType==FUZZ_CHANGE_DEL ){
822       if( pGrp->nChange==1 ) return -1;
823       pOut = *ppOut;
824     }
825     if( eNew!=eType && eNew==SQLITE_UPDATE ){
826       int i;
827       u8 *pCsr = (*ppOut) + 2;
828       for(i=0; i<pGrp->nCol; i++){
829         int sz;
830         u8 *pCopy = pCsr;
831         if( pGrp->aPK[i] ) pCopy = "\0";
832         fuzzChangeSize(pCopy, &sz);
833         memcpy(pOut, pCopy, sz);
834         pOut += sz;
835         fuzzChangeSize(pCsr, &sz);
836         pCsr += sz;
837       }
838     }
839   }
840 
841   *pp = p;
842   *ppOut = pOut;
843   pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
844   return SQLITE_OK;
845 }
846 
847 static int fuzzDoOneFuzz(
848   const char *zOut,               /* Filename to write modified changeset to */
849   u8 *pBuf,                       /* Buffer to use for modified changeset */
850   FuzzChangeset *pParse           /* Parse of input changeset */
851 ){
852   FuzzChange change;
853   int iGrp;
854   int rc = -1;
855 
856   while( rc<0 ){
857     u8 *pOut = pBuf;
858     rc = fuzzSelectChange(pParse, &change);
859     for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
860       FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
861       int nTab = strlen(pGrp->zTab) + 1;
862       u8 *p;
863       int i;
864 
865       /* Output a table header */
866       pOut++[0] = 'T';
867       pOut += fuzzPutVarint(pOut, pGrp->nCol);
868       memcpy(pOut, pGrp->aPK, pGrp->nCol);
869       pOut += pGrp->nCol;
870       memcpy(pOut, pGrp->zTab, nTab);
871       pOut += nTab;
872 
873       /* Output the change array */
874       p = pGrp->aChange;
875       for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
876         rc = fuzzCopyChange(pParse, pGrp, &change, &p, &pOut);
877       }
878     }
879     if( rc==SQLITE_OK ){
880       fuzzWriteFile(zOut, pBuf, pOut-pBuf);
881     }
882   }
883 
884   return rc;
885 }
886 
887 int main(int argc, char **argv){
888   int nRepeat = 0;                /* Number of output files */
889   int iSeed = 0;                  /* Value of PRNG seed */
890   const char *zInput;             /* Name of input file */
891   void *pChangeset = 0;           /* Input changeset */
892   int nChangeset = 0;             /* Size of input changeset in bytes */
893   int i;                          /* Current output file */
894   FuzzChangeset changeset;        /* Partially parsed changeset */
895   int rc;
896   u8 *pBuf = 0;
897 
898   if( argc!=4 && argc!=2 ) usage(argv[0]);
899   zInput = argv[1];
900 
901   fuzzReadFile(zInput, &nChangeset, &pChangeset);
902   rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset);
903 
904   if( rc==SQLITE_OK ){
905     if( argc==2 ){
906       for(i=0; i<changeset.nGroup; i++){
907         fuzzPrintGroup(changeset.apGroup[i]);
908       }
909     }else{
910       pBuf = (u8*)fuzzMalloc(nChangeset*2 + 1024);
911       if( pBuf==0 ){
912         rc = SQLITE_NOMEM;
913       }else{
914         iSeed = atoi(argv[2]);
915         nRepeat = atoi(argv[3]);
916         fuzzRandomSeed((unsigned int)iSeed);
917         for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
918           char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
919           fuzzDoOneFuzz(zOut, pBuf, &changeset);
920           sqlite3_free(zOut);
921         }
922         fuzzFree(pBuf);
923       }
924     }
925   }
926 
927   if( rc!=SQLITE_OK ){
928     fprintf(stderr, "error while processing changeset: %d\n", rc);
929   }
930   return rc;
931 }
932 
933