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