bump version number to 4.5.6
[sqlcipher.git] / ext / session / changesetfuzz.c
blobbbd72f6d9dde07770194c3c1b068fa2e7691fa9a
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.
11 *************************************************************************
12 ** This file contains code to implement the "changesetfuzz" command
13 ** line utility for fuzzing changeset blobs without corrupting them.
17 /************************************************************************
18 ** USAGE:
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
31 ** point on.
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
50 ** generated value.
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
55 ** well-formed.
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
69 ** values.
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.
99 #include "sqlite3.h"
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <assert.h>
104 #include <ctype.h>
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);
136 exit(1);
140 ** Read the content of a disk file into an in-memory buffer
142 static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
143 FILE *f;
144 sqlite3_int64 sz;
145 void *pBuf;
146 f = fopen(zFilename, "rb");
147 if( f==0 ){
148 fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
149 exit(1);
151 fseek(f, 0, SEEK_END);
152 sz = ftell(f);
153 rewind(f);
154 pBuf = sqlite3_malloc64( sz ? sz : 1 );
155 if( pBuf==0 ){
156 fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
157 (int)sz, zFilename);
158 exit(1);
160 if( sz>0 ){
161 if( fread(pBuf, (size_t)sz, 1, f)!=1 ){
162 fprintf(stderr, "cannot read all %d bytes of \"%s\"\n",
163 (int)sz, zFilename);
164 exit(1);
166 fclose(f);
168 *pSz = (int)sz;
169 *ppBuf = pBuf;
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){
177 FILE *f;
178 f = fopen(zFilename, "wb");
179 if( f==0 ){
180 fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename);
181 exit(1);
183 if( fwrite(pBuf, nBuf, 1, f)!=1 ){
184 fprintf(stderr, "cannot write to \"%s\"\n", zFilename);
185 exit(1);
187 fclose(f);
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 */
206 } sqlite3Prng = {
207 0xAF, 0x28,
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){
248 unsigned char t;
249 sqlite3Prng.i++;
250 t = sqlite3Prng.s[sqlite3Prng.i];
251 sqlite3Prng.j += t;
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){
262 int i;
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){
272 unsigned int ret;
273 assert( nRange>0 );
274 fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
275 return (ret % nRange);
278 static u64 fuzzRandomU64(){
279 u64 ret;
280 fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
281 return ret;
284 static void fuzzRandomSeed(unsigned int iSeed){
285 int i;
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.
330 struct FuzzChange {
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);
346 if( pRet ){
347 memset(pRet, 0, (size_t)nByte);
349 return pRet;
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){
357 sqlite3_free(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){
367 int i;
368 sqlite3_uint64 nVal = 0;
369 for(i=0; i<9; i++){
370 nVal = (nVal<<7) + (p[i] & 0x7F);
371 if( (p[i] & 0x80)==0 ){
372 i++;
373 break;
376 *pnVal = (int)nVal;
377 return i;
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 );
387 if( nVal<128 ){
388 p[0] = (u8)nVal;
389 return 1;
391 if( nVal<16384 ){
392 p[0] = ((nVal >> 7) & 0x7F) | 0x80;
393 p[1] = (nVal & 0x7F);
394 return 2;
397 p[0] = ((nVal >> 14) & 0x7F) | 0x80;
398 p[1] = ((nVal >> 7) & 0x7F) | 0x80;
399 p[2] = (nVal & 0x7F);
400 return 3;
404 ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
405 ** the value read.
407 static i64 fuzzGetI64(u8 *aRec){
408 return (i64)(
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
437 ** otherwise.
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 */
445 int rc = SQLITE_OK;
446 FuzzChangesetGroup *pGrp;
447 u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
449 assert( pEnd>(*ppHdr) );
450 pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
451 if( !pGrp ){
452 rc = SQLITE_NOMEM;
453 }else{
454 u8 *p = *ppHdr;
455 if( p[0]!=cHdr ){
456 rc = fuzzCorrupt();
457 }else{
458 p++;
459 p += fuzzGetVarint(p, &pGrp->nCol);
460 pGrp->aPK = p;
461 p += pGrp->nCol;
462 pGrp->zTab = (const char*)p;
463 p = &p[strlen((const char*)p)+1];
465 if( p>=pEnd ){
466 rc = fuzzCorrupt();
469 *ppHdr = p;
472 if( rc!=SQLITE_OK ){
473 fuzzFree(pGrp);
474 pGrp = 0;
477 *ppGrp = pGrp;
478 return rc;
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){
489 u8 eType = p[0];
490 switch( eType ){
491 case 0x00: /* undefined */
492 case 0x05: /* null */
493 *pSz = 1;
494 break;
496 case 0x01: /* integer */
497 case 0x02: /* real */
498 *pSz = 9;
499 break;
501 case 0x03: /* text */
502 case 0x04: { /* blob */
503 int nTxt;
504 int sz;
505 sz = fuzzGetVarint(&p[1], &nTxt);
506 *pSz = 1 + sz + nTxt;
507 break;
510 default:
511 return fuzzCorrupt();
513 return SQLITE_OK;
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 */
535 int rc = SQLITE_OK;
536 FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
537 int i;
538 u8 *p = *ppRec;
540 for(i=0; rc==SQLITE_OK && i<pGrp->nCol; i++){
541 if( bPkOnly==0 || pGrp->aPK[i] ){
542 int sz;
543 if( p>=pEnd ) break;
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);
552 p += sz;
556 if( rc==SQLITE_OK && i<pGrp->nCol ){
557 rc = fuzzCorrupt();
560 *ppRec = p;
561 return rc;
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];
575 int rc = SQLITE_OK;
576 u8 *p = *ppData;
578 pGrp->aChange = p;
579 while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){
580 u8 eOp = p[0];
581 u8 bIndirect = p[1];
583 p += 2;
584 if( eOp==SQLITE_UPDATE ){
585 pParse->nUpdate++;
586 if( pParse->bPatchset==0 ){
587 rc = fuzzParseRecord(&p, pEnd, pParse, 0);
589 }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
590 rc = fuzzCorrupt();
592 if( rc==SQLITE_OK ){
593 int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset);
594 rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly);
596 pGrp->nChange++;
597 pParse->nChange++;
599 pGrp->szChange = p - pGrp->aChange;
601 *ppData = p;
602 return rc;
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];
617 u8 *p = pChangeset;
618 int rc = SQLITE_OK;
620 memset(pParse, 0, sizeof(FuzzChangeset));
621 if( nChangeset>0 ){
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. */
634 if( rc==SQLITE_OK ){
635 FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc64(
636 pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
638 if( apNew==0 ){
639 rc = SQLITE_NOMEM;
640 }else{
641 apNew[pParse->nGroup] = pGrp;
642 pParse->apGroup = apNew;
643 pParse->nGroup++;
645 rc = fuzzParseChanges(&p, pEnd, pParse);
649 return rc;
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
658 ** error code.
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){
665 int rc = SQLITE_OK;
666 u8 *p = *ppRec;
667 int i;
668 const char *zPre = " (";
670 for(i=0; i<pGrp->nCol; i++){
671 if( bPKOnly==0 || pGrp->aPK[i] ){
672 u8 eType = p++[0];
673 switch( eType ){
674 case 0x00: /* undefined */
675 printf("%sn/a", zPre);
676 break;
678 case 0x01: { /* integer */
679 sqlite3_int64 iVal = 0;
680 iVal = fuzzGetI64(p);
681 printf("%s%lld", zPre, iVal);
682 p += 8;
683 break;
686 case 0x02: { /* real */
687 sqlite3_int64 iVal = 0;
688 double fVal = 0.0;
689 iVal = fuzzGetI64(p);
690 memcpy(&fVal, &iVal, 8);
691 printf("%s%f", zPre, fVal);
692 p += 8;
693 break;
696 case 0x03: /* text */
697 case 0x04: { /* blob */
698 int nTxt;
699 p += fuzzGetVarint(p, &nTxt);
700 printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
701 for(i=0; i<nTxt; i++){
702 if( eType==0x03 ){
703 printf("%c", p[i]);
704 }else{
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 ]);
712 printf("'");
713 p += nTxt;
714 break;
717 case 0x05: /* null */
718 printf("%sNULL", zPre);
719 break;
721 zPre = ", ";
724 printf(")");
726 *ppRec = p;
727 return rc;
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){
735 int i;
736 u8 *p;
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]);
743 printf("\n");
745 /* The array of changes */
746 p = pGrp->aChange;
747 for(i=0; i<pGrp->nChange; i++){
748 u8 eType = p[0];
749 u8 bIndirect = p[1];
750 printf("%s (ind=%d):",
751 (eType==SQLITE_INSERT) ? "INSERT" :
752 (eType==SQLITE_DELETE ? "DELETE" : "UPDATE"),
753 bIndirect
755 p += 2;
757 if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){
758 fuzzPrintRecord(pGrp, &p, 0);
760 fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
761 printf("\n");
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){
776 int iSub;
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];
807 int i;
808 pChange->iDelete = fuzzRandomInt(pGrp->nCol);
809 for(i=pGrp->nCol-1; i>=0; i--){
810 if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
812 if( i<0 ) return -1;
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];
836 }else{
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);
846 break;
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);
855 break;
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 ){
864 int i;
865 for(i=0; i<nByte; i++){
866 pChange->aSub[2+i] &= 0x7F;
869 break;
873 if( pChange->eType==FUZZ_VALUE_MOD ){
874 int sz;
875 int iMod = -1;
876 fuzzChangeSize(pChange->pSub1, &sz);
877 memcpy(pChange->aSub, pChange->pSub1, sz);
878 switch( pChange->aSub[0] ){
879 case 0x01:
880 case 0x02:
881 iMod = fuzzRandomInt(8) + 1;
882 break;
884 case 0x03: /* text */
885 case 0x04: { /* blob */
886 int nByte;
887 int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte);
888 if( nByte>0 ){
889 iMod = fuzzRandomInt(nByte) + iFirst;
891 break;
895 if( iMod>=0 ){
896 u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03)));
897 pChange->aSub[iMod] ^= mask;
902 return SQLITE_OK;
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,
911 int iGrp,
912 FuzzChange *pFuzz,
913 u8 **pp, u8 **ppOut /* IN/OUT: Input and output pointers */
915 int bPS = pParse->bPatchset;
916 FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
917 u8 *p = *pp;
918 u8 *pOut = *ppOut;
919 u8 eType = p++[0];
920 int iRec;
921 int nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1);
922 int iUndef = -1;
923 int nUpdate = 0;
925 u8 eNew = eType;
926 if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
927 switch( eType ){
928 case SQLITE_INSERT:
929 eNew = SQLITE_DELETE;
930 break;
931 case SQLITE_DELETE:
932 eNew = SQLITE_UPDATE;
933 break;
934 case SQLITE_UPDATE:
935 eNew = SQLITE_INSERT;
936 break;
940 if( pFuzz->iCurrent==pFuzz->iChange
941 && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE
943 int sz;
944 int i;
945 int nDef = 0;
946 u8 *pCsr = p+1;
947 for(i=0; i<pGrp->nCol; i++){
948 if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++;
949 fuzzChangeSize(pCsr, &sz);
950 pCsr += sz;
952 if( nDef<=1 ) return -1;
953 nDef = fuzzRandomInt(nDef);
954 pCsr = p+1;
955 for(i=0; i<pGrp->nCol; i++){
956 if( pCsr[0] && pGrp->aPK[i]==0 ){
957 if( nDef==0 ) iUndef = i;
958 nDef--;
960 fuzzChangeSize(pCsr, &sz);
961 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. */
968 *(pOut++) = eNew;
969 if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
970 *(pOut++) = !(*(p++));
971 }else{
972 *(pOut++) = *(p++);
975 for(iRec=0; iRec<nRec; iRec++){
976 int i;
978 /* Copy the next record from the output to the input.
980 for(i=0; i<pGrp->nCol; i++){
981 int sz;
982 u8 *pCopy = p;
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 ){
989 if( eType!=eNew ){
990 assert( eNew==SQLITE_UPDATE );
991 do {
992 pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
993 }while( pCopy[0]==0x00 );
994 fuzzChangeSize(pCopy, &sz);
995 memcpy(pOut, pCopy, sz);
996 pOut += sz;
998 continue;
1001 if( p==pFuzz->pSub1 ){
1002 pCopy = pFuzz->pSub2;
1003 }else if( p==pFuzz->pSub2 ){
1004 pCopy = pFuzz->pSub1;
1005 }else if( i==iUndef ){
1006 pCopy = (u8*)"\0";
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 ){
1014 return -1;
1015 }else{
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);
1025 pOut += sz;
1026 nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
1029 fuzzChangeSize(p, &sz);
1030 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 ){
1037 if( iRec==1 ){
1038 *(pOut++) = 0x00;
1039 }else{
1040 u8 *pNew;
1041 int szNew;
1042 do {
1043 pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
1044 }while( pNew[0]==0x00 || pNew[0]==0x05 );
1045 fuzzChangeSize(pNew, &szNew);
1046 memcpy(pOut, pNew, szNew);
1047 pOut += szNew;
1053 if( pFuzz->iCurrent==pFuzz->iChange ){
1054 if( pFuzz->eType==FUZZ_CHANGE_DUP ){
1055 int nByte = pOut - (*ppOut);
1056 memcpy(pOut, *ppOut, nByte);
1057 pOut += nByte;
1060 if( pFuzz->eType==FUZZ_CHANGE_DEL ){
1061 pOut = *ppOut;
1063 if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){
1064 int i;
1065 u8 *pCsr = (*ppOut) + 2;
1066 for(i=0; i<pGrp->nCol; i++){
1067 int sz;
1068 u8 *pCopy = pCsr;
1069 if( pGrp->aPK[i] ) pCopy = (u8*)"\0";
1070 fuzzChangeSize(pCopy, &sz);
1071 memcpy(pOut, pCopy, sz);
1072 pOut += sz;
1073 fuzzChangeSize(pCsr, &sz);
1074 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
1085 pOut = *ppOut;
1088 *pp = p;
1089 *ppOut = pOut;
1090 pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
1091 return SQLITE_OK;
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 */
1106 FuzzChange change;
1107 int iGrp;
1108 int rc = -1;
1110 while( rc<0 ){
1111 u8 *pOut = pBuf;
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;
1116 int j;
1117 int nRep = 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;
1128 continue;
1130 else if( change.eType==FUZZ_GROUP_DUP ){
1131 nRep = 2;
1135 for(j=0; j<nRep; j++){
1136 int i;
1137 u8 *pSaved;
1138 u8 *p = pGrp->aChange;
1139 int nCol = pGrp->nCol;
1140 int iPKDel = 0;
1141 if( iGrp==change.iGroup ){
1142 if( change.eType==FUZZ_COLUMN_ADD
1143 || change.eType==FUZZ_COLUMN_ADDPK
1145 nCol++;
1146 }else if( change.eType==FUZZ_COLUMN_DEL ){
1147 nCol--;
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--;
1160 *(pOut++) = v;
1163 if( nCol>pGrp->nCol ){
1164 if( change.eType==FUZZ_COLUMN_ADD ){
1165 *(pOut++) = 0x00;
1166 }else{
1167 u8 max = 0;
1168 for(i=0; i<pGrp->nCol; i++){
1169 if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
1171 *(pOut++) = max+1;
1174 memcpy(pOut, pGrp->zTab, nTab);
1175 pOut += nTab;
1177 /* Output the change array. */
1178 pSaved = pOut;
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);
1190 return rc;
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 */
1201 int rc;
1202 u8 *pBuf = 0;
1204 if( argc!=4 && argc!=2 ) usage(argv[0]);
1205 zInput = argv[1];
1207 fuzzReadFile(zInput, &nChangeset, &pChangeset);
1208 rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset);
1210 if( rc==SQLITE_OK ){
1211 if( argc==2 ){
1212 for(i=0; i<changeset.nGroup; i++){
1213 fuzzPrintGroup(&changeset, changeset.apGroup[i]);
1215 }else{
1216 pBuf = (u8*)fuzzMalloc((sqlite3_int64)nChangeset*2 + 1024);
1217 if( pBuf==0 ){
1218 rc = SQLITE_NOMEM;
1219 }else{
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);
1226 sqlite3_free(zOut);
1228 fuzzFree(pBuf);
1233 if( rc!=SQLITE_OK ){
1234 fprintf(stderr, "error while processing changeset: %d\n", rc);
1237 return rc;