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 ** 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. 32 ** 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. 41 ** 42 ** The ways in which an input changeset may be fuzzed are as follows: 43 ** 44 ** 1. Any two values within the changeset may be exchanged. 45 ** 46 ** 2. Any TEXT, BLOB, INTEGER or REAL value within the changeset 47 ** may have a single bit of its content flipped. 48 ** 49 ** 3. Any value within a changeset may be replaced by a pseudo-randomly 50 ** generated value. 51 ** 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. 56 ** 57 ** 4. A single change may be duplicated. 58 ** 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. 61 ** 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. 70 ** 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). 73 ** 74 ** 8. The "indirect" flag may be toggled for any change. 75 ** 76 ** Entire group of changes may also be operated on: 77 ** 78 ** 9. Duplicate an existing group. 79 ** 80 ** 10. Remove an existing group. 81 ** 82 ** 11. The positions of two groups may be exchanged. 83 ** 84 ** There are also schema changes: 85 ** 86 ** 12. A non-PK column may be added to a table. In this case a NULL 87 ** value is appended to all records. 88 ** 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. 92 ** 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. 97 */ 98 99 #include "sqlite3.h" 100 #include <stdio.h> 101 #include <stdlib.h> 102 #include <string.h> 103 #include <assert.h> 104 #include <ctype.h> 105 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 */ 109 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 */ 115 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 */ 119 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 */ 123 124 125 126 typedef unsigned char u8; 127 typedef sqlite3_uint64 u64; 128 typedef sqlite3_int64 i64; 129 typedef unsigned int u32; 130 131 /* 132 ** Show a usage message on stderr then quit. 133 */ 134 static void usage(const char *argv0){ 135 fprintf(stderr, "Usage: %s FILENAME ?SEED N?\n", argv0); 136 exit(1); 137 } 138 139 /* 140 ** Read the content of a disk file into an in-memory buffer 141 */ 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); 150 } 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); 159 } 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); 165 } 166 fclose(f); 167 } 168 *pSz = (int)sz; 169 *ppBuf = pBuf; 170 } 171 172 /* 173 ** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename 174 ** on disk. zFilename, if it already exists, is clobbered. 175 */ 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); 182 } 183 if( fwrite(pBuf, nBuf, 1, f)!=1 ){ 184 fprintf(stderr, "cannot write to \"%s\"\n", zFilename); 185 exit(1); 186 } 187 fclose(f); 188 } 189 190 static int fuzzCorrupt(){ 191 return SQLITE_CORRUPT; 192 } 193 194 /************************************************************************* 195 ** The following block is a copy of the implementation of SQLite function 196 ** sqlite3_randomness. This version has two important differences: 197 ** 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. 200 ** 201 ** 2. It is not threadsafe. 202 */ 203 static struct sqlite3PrngType { 204 unsigned char i, j; /* State variables */ 205 unsigned char s[256]; /* State variables */ 206 } sqlite3Prng = { 207 0xAF, 0x28, 208 { 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 241 } 242 }; 243 244 /* 245 ** Generate and return single random byte 246 */ 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]; 256 } 257 258 /* 259 ** Return N random bytes. 260 */ 261 static void fuzzRandomBlob(int nBuf, unsigned char *zBuf){ 262 int i; 263 for(i=0; i<nBuf; i++){ 264 zBuf[i] = fuzzRandomByte(); 265 } 266 } 267 268 /* 269 ** Return a random integer between 0 and nRange (not inclusive). 270 */ 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); 276 } 277 278 static u64 fuzzRandomU64(){ 279 u64 ret; 280 fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret); 281 return ret; 282 } 283 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); 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 /* 302 ** Object containing partially parsed changeset. 303 */ 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 */ 312 }; 313 314 /* 315 ** There is one object of this type for each change-group (table header) 316 ** in the input changeset. 317 */ 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[] */ 325 }; 326 327 /* 328 ** Description of a fuzz change to be applied to a changeset. 329 */ 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 */ 339 }; 340 341 /* 342 ** Allocate and return nByte bytes of zeroed memory. 343 */ 344 static void *fuzzMalloc(sqlite3_int64 nByte){ 345 void *pRet = sqlite3_malloc64(nByte); 346 if( pRet ){ 347 memset(pRet, 0, (size_t)nByte); 348 } 349 return pRet; 350 } 351 352 /* 353 ** Free the buffer indicated by the first argument. This function is used 354 ** to free buffers allocated by fuzzMalloc(). 355 */ 356 static void fuzzFree(void *p){ 357 sqlite3_free(p); 358 } 359 360 /* 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. 365 */ 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; 374 } 375 } 376 *pnVal = (int)nVal; 377 return i; 378 } 379 380 /* 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. 384 */ 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; 390 } 391 if( nVal<16384 ){ 392 p[0] = ((nVal >> 7) & 0x7F) | 0x80; 393 p[1] = (nVal & 0x7F); 394 return 2; 395 } 396 397 p[0] = ((nVal >> 14) & 0x7F) | 0x80; 398 p[1] = ((nVal >> 7) & 0x7F) | 0x80; 399 p[2] = (nVal & 0x7F); 400 return 3; 401 } 402 403 /* 404 ** Read a 64-bit big-endian integer value from buffer aRec[]. Return 405 ** the value read. 406 */ 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) 417 ); 418 } 419 420 /* 421 ** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer. 422 */ 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; 432 } 433 434 /* 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. 438 */ 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 */ 444 ){ 445 int rc = SQLITE_OK; 446 FuzzChangesetGroup *pGrp; 447 u8 cHdr = (pParse->bPatchset ? 'P' : 'T'); 448 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]; 464 465 if( p>=pEnd ){ 466 rc = fuzzCorrupt(); 467 } 468 } 469 *ppHdr = p; 470 } 471 472 if( rc!=SQLITE_OK ){ 473 fuzzFree(pGrp); 474 pGrp = 0; 475 } 476 477 *ppGrp = pGrp; 478 return rc; 479 } 480 481 /* 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. 487 */ 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; 495 496 case 0x01: /* integer */ 497 case 0x02: /* real */ 498 *pSz = 9; 499 break; 500 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; 508 } 509 510 default: 511 return fuzzCorrupt(); 512 } 513 return SQLITE_OK; 514 } 515 516 /* 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. 522 ** 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. 526 ** 527 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. 528 */ 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 */ 534 ){ 535 int rc = SQLITE_OK; 536 FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1]; 537 int i; 538 u8 *p = *ppRec; 539 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; 549 } 550 pParse->apVal[pParse->nVal++] = p; 551 rc = fuzzChangeSize(p, &sz); 552 p += sz; 553 } 554 } 555 556 if( rc==SQLITE_OK && i<pGrp->nCol ){ 557 rc = fuzzCorrupt(); 558 } 559 560 *ppRec = p; 561 return rc; 562 } 563 564 /* 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. 571 */ 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; 577 578 pGrp->aChange = p; 579 while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){ 580 u8 eOp = p[0]; 581 u8 bIndirect = p[1]; 582 583 p += 2; 584 if( eOp==SQLITE_UPDATE ){ 585 pParse->nUpdate++; 586 if( pParse->bPatchset==0 ){ 587 rc = fuzzParseRecord(&p, pEnd, pParse, 0); 588 } 589 }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){ 590 rc = fuzzCorrupt(); 591 } 592 if( rc==SQLITE_OK ){ 593 int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset); 594 rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly); 595 } 596 pGrp->nChange++; 597 pParse->nChange++; 598 } 599 pGrp->szChange = p - pGrp->aChange; 600 601 *ppData = p; 602 return rc; 603 } 604 605 /* 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. 610 */ 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 */ 615 ){ 616 u8 *pEnd = &pChangeset[nChangeset]; 617 u8 *p = pChangeset; 618 int rc = SQLITE_OK; 619 620 memset(pParse, 0, sizeof(FuzzChangeset)); 621 if( nChangeset>0 ){ 622 pParse->bPatchset = (pChangeset[0]=='P'); 623 } 624 625 while( rc==SQLITE_OK && p<pEnd ){ 626 FuzzChangesetGroup *pGrp = 0; 627 628 /* Read a table-header from the changeset */ 629 rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp); 630 assert( (rc==SQLITE_OK)==(pGrp!=0) ); 631 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) 637 ); 638 if( apNew==0 ){ 639 rc = SQLITE_NOMEM; 640 }else{ 641 apNew[pParse->nGroup] = pGrp; 642 pParse->apGroup = apNew; 643 pParse->nGroup++; 644 } 645 rc = fuzzParseChanges(&p, pEnd, pParse); 646 } 647 } 648 649 return rc; 650 } 651 652 /* 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. 659 ** 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. 663 */ 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 = " ("; 669 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; 677 678 case 0x01: { /* integer */ 679 sqlite3_int64 iVal = 0; 680 iVal = fuzzGetI64(p); 681 printf("%s%lld", zPre, iVal); 682 p += 8; 683 break; 684 } 685 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; 694 } 695 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' 707 }; 708 printf("%c", aHex[ p[i]>>4 ]); 709 printf("%c", aHex[ p[i] & 0x0F ]); 710 } 711 } 712 printf("'"); 713 p += nTxt; 714 break; 715 } 716 717 case 0x05: /* null */ 718 printf("%sNULL", zPre); 719 break; 720 } 721 zPre = ", "; 722 } 723 } 724 printf(")"); 725 726 *ppRec = p; 727 return rc; 728 } 729 730 /* 731 ** Print a human-readable version of the table-header and all changes in the 732 ** change-group passed as the second argument. 733 */ 734 static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){ 735 int i; 736 u8 *p; 737 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]); 742 } 743 printf("\n"); 744 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 754 ); 755 p += 2; 756 757 if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){ 758 fuzzPrintRecord(pGrp, &p, 0); 759 } 760 fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset); 761 printf("\n"); 762 } 763 } 764 765 /* 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. 770 ** 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. 774 */ 775 static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){ 776 int iSub; 777 778 memset(pChange, 0, sizeof(FuzzChange)); 779 pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1; 780 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 795 ); 796 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); 802 } 803 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; 811 } 812 if( i<0 ) return -1; 813 } 814 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); 821 } 822 pGrp = pParse->apGroup[pChange->iGroup]; 823 pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp]; 824 pParse->apGroup[iGrp] = pGrp; 825 } 826 827 if( pChange->eType==FUZZ_VALUE_SUB 828 || pChange->eType==FUZZ_VALUE_MOD 829 || pChange->eType==FUZZ_VALUE_RND 830 ){ 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; 838 } 839 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; 847 } 848 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; 856 } 857 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; 867 } 868 } 869 break; 870 } 871 } 872 } 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; 883 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; 890 } 891 break; 892 } 893 } 894 895 if( iMod>=0 ){ 896 u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03))); 897 pChange->aSub[iMod] ^= mask; 898 } 899 } 900 } 901 902 return SQLITE_OK; 903 } 904 905 /* 906 ** Copy a single change from the input to the output changeset, making 907 ** any modifications specified by (*pFuzz). 908 */ 909 static int fuzzCopyChange( 910 FuzzChangeset *pParse, 911 int iGrp, 912 FuzzChange *pFuzz, 913 u8 **pp, u8 **ppOut /* IN/OUT: Input and output pointers */ 914 ){ 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; 924 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; 937 } 938 } 939 940 if( pFuzz->iCurrent==pFuzz->iChange 941 && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE 942 ){ 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; 951 } 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--; 959 } 960 fuzzChangeSize(pCsr, &sz); 961 pCsr += sz; 962 } 963 } 964 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++); 973 } 974 975 for(iRec=0; iRec<nRec; iRec++){ 976 int i; 977 978 /* Copy the next record from the output to the input. 979 */ 980 for(i=0; i<pGrp->nCol; i++){ 981 int sz; 982 u8 *pCopy = p; 983 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; 997 } 998 continue; 999 } 1000 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"; 1007 } 1008 1009 if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){ 1010 while( pCopy[0]==0x00 ){ 1011 pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)]; 1012 } 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; 1017 } 1018 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]) 1022 ){ 1023 fuzzChangeSize(pCopy, &sz); 1024 memcpy(pOut, pCopy, sz); 1025 pOut += sz; 1026 nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00); 1027 } 1028 1029 fuzzChangeSize(p, &sz); 1030 p += sz; 1031 } 1032 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; 1048 } 1049 } 1050 } 1051 } 1052 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; 1058 } 1059 1060 if( pFuzz->eType==FUZZ_CHANGE_DEL ){ 1061 pOut = *ppOut; 1062 } 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; 1075 } 1076 } 1077 } 1078 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 1084 ){ 1085 pOut = *ppOut; 1086 } 1087 1088 *pp = p; 1089 *ppOut = pOut; 1090 pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD); 1091 return SQLITE_OK; 1092 } 1093 1094 /* 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. 1098 ** 1099 ** Return SQLITE_OK if successful, or an SQLite error code if an error occurs. 1100 */ 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 */ 1105 ){ 1106 FuzzChange change; 1107 int iGrp; 1108 int rc = -1; 1109 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; 1118 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. 1122 ** 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; 1129 } 1130 else if( change.eType==FUZZ_GROUP_DUP ){ 1131 nRep = 2; 1132 } 1133 } 1134 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 1144 ){ 1145 nCol++; 1146 }else if( change.eType==FUZZ_COLUMN_DEL ){ 1147 nCol--; 1148 iPKDel = pGrp->aPK[change.iDelete]; 1149 } 1150 } 1151 1152 /* Output a table header */ 1153 pOut++[0] = pParse->bPatchset ? 'P' : 'T'; 1154 pOut += fuzzPutVarint(pOut, nCol); 1155 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; 1161 } 1162 } 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]; 1170 } 1171 *(pOut++) = max+1; 1172 } 1173 } 1174 memcpy(pOut, pGrp->zTab, nTab); 1175 pOut += nTab; 1176 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); 1181 } 1182 if( pOut==pSaved ) rc = -1; 1183 } 1184 } 1185 if( rc==SQLITE_OK ){ 1186 fuzzWriteFile(zOut, pBuf, pOut-pBuf); 1187 } 1188 } 1189 1190 return rc; 1191 } 1192 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; 1203 1204 if( argc!=4 && argc!=2 ) usage(argv[0]); 1205 zInput = argv[1]; 1206 1207 fuzzReadFile(zInput, &nChangeset, &pChangeset); 1208 rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset); 1209 1210 if( rc==SQLITE_OK ){ 1211 if( argc==2 ){ 1212 for(i=0; i<changeset.nGroup; i++){ 1213 fuzzPrintGroup(&changeset, changeset.apGroup[i]); 1214 } 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); 1227 } 1228 fuzzFree(pBuf); 1229 } 1230 } 1231 } 1232 1233 if( rc!=SQLITE_OK ){ 1234 fprintf(stderr, "error while processing changeset: %d\n", rc); 1235 } 1236 1237 return rc; 1238 } 1239