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 int 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 = (int)ftell(f); 153 rewind(f); 154 pBuf = sqlite3_malloc( sz ? sz : 1 ); 155 if( pBuf==0 ){ 156 fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n", 157 sz, zFilename); 158 exit(1); 159 } 160 if( sz>0 ){ 161 if( fread(pBuf, sz, 1, f)!=1 ){ 162 fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", sz, zFilename); 163 exit(1); 164 } 165 fclose(f); 166 } 167 *pSz = sz; 168 *ppBuf = pBuf; 169 } 170 171 /* 172 ** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename 173 ** on disk. zFilename, if it already exists, is clobbered. 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 ** End of code for generating pseudo-random values. 294 *************************************************************************/ 295 296 typedef struct FuzzChangeset FuzzChangeset; 297 typedef struct FuzzChangesetGroup FuzzChangesetGroup; 298 typedef struct FuzzChange FuzzChange; 299 300 /* 301 ** Object containing partially parsed changeset. 302 */ 303 struct FuzzChangeset { 304 int bPatchset; /* True for a patchset */ 305 FuzzChangesetGroup **apGroup; /* Array of groups in changeset */ 306 int nGroup; /* Number of items in list pGroup */ 307 u8 **apVal; /* Array of all values in changeset */ 308 int nVal; /* Number of used slots in apVal[] */ 309 int nChange; /* Number of changes in changeset */ 310 int nUpdate; /* Number of UPDATE changes in changeset */ 311 }; 312 313 /* 314 ** There is one object of this type for each change-group (table header) 315 ** in the input changeset. 316 */ 317 struct FuzzChangesetGroup { 318 const char *zTab; /* Name of table */ 319 int nCol; /* Number of columns in table */ 320 u8 *aPK; /* PK array for this table */ 321 u8 *aChange; /* Buffer containing array of changes */ 322 int szChange; /* Size of buffer aChange[] in bytes */ 323 int nChange; /* Number of changes in buffer aChange[] */ 324 }; 325 326 /* 327 ** Description of a fuzz change to be applied to a changeset. 328 */ 329 struct FuzzChange { 330 int eType; /* One of the FUZZ_* constants above */ 331 int iChange; /* Change or UPDATE to modify */ 332 int iGroup; /* Group to modify */ 333 int iDelete; /* Field to remove (FUZZ_COLUMN_DEL) */ 334 u8 *pSub1; /* Replace this value with pSub2 */ 335 u8 *pSub2; /* And this one with pSub1 */ 336 u8 aSub[128]; /* Buffer for substitute value */ 337 int iCurrent; /* Current change number */ 338 }; 339 340 /* 341 ** Allocate and return nByte bytes of zeroed memory. 342 */ 343 static void *fuzzMalloc(int nByte){ 344 void *pRet = sqlite3_malloc(nByte); 345 if( pRet ){ 346 memset(pRet, 0, nByte); 347 } 348 return pRet; 349 } 350 351 /* 352 ** Free the buffer indicated by the first argument. This function is used 353 ** to free buffers allocated by fuzzMalloc(). 354 */ 355 static void fuzzFree(void *p){ 356 sqlite3_free(p); 357 } 358 359 /* 360 ** Argument p points to a buffer containing an SQLite varint that, assuming the 361 ** input is not corrupt, may be between 0 and 0x7FFFFFFF, inclusive. Before 362 ** returning, this function sets (*pnVal) to the value of that varint, and 363 ** returns the number of bytes of space that it takes up. 364 */ 365 static int fuzzGetVarint(u8 *p, int *pnVal){ 366 int i; 367 sqlite3_uint64 nVal = 0; 368 for(i=0; i<9; i++){ 369 nVal = (nVal<<7) + (p[i] & 0x7F); 370 if( (p[i] & 0x80)==0 ){ 371 i++; 372 break; 373 } 374 } 375 *pnVal = (int)nVal; 376 return i; 377 } 378 379 /* 380 ** Write value nVal into the buffer indicated by argument p as an SQLite 381 ** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive. 382 ** Return the number of bytes written to buffer p. 383 */ 384 static int fuzzPutVarint(u8 *p, int nVal){ 385 assert( nVal>0 && nVal<2097152 ); 386 if( nVal<128 ){ 387 p[0] = nVal; 388 return 1; 389 } 390 if( nVal<16384 ){ 391 p[0] = ((nVal >> 7) & 0x7F) | 0x80; 392 p[1] = (nVal & 0x7F); 393 return 2; 394 } 395 396 p[0] = ((nVal >> 14) & 0x7F) | 0x80; 397 p[1] = ((nVal >> 7) & 0x7F) | 0x80; 398 p[2] = (nVal & 0x7F); 399 return 3; 400 } 401 402 /* 403 ** Read a 64-bit big-endian integer value from buffer aRec[]. Return 404 ** the value read. 405 */ 406 static i64 fuzzGetI64(u8 *aRec){ 407 return (i64)( 408 (((u64)aRec[0]) << 56) 409 + (((u64)aRec[1]) << 48) 410 + (((u64)aRec[2]) << 40) 411 + (((u64)aRec[3]) << 32) 412 + (((u64)aRec[4]) << 24) 413 + (((u64)aRec[5]) << 16) 414 + (((u64)aRec[6]) << 8) 415 + (((u64)aRec[7]) << 0) 416 ); 417 } 418 419 /* 420 ** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer. 421 */ 422 static void fuzzPutU64(u8 *aRec, u64 iVal){ 423 aRec[0] = (iVal>>56) & 0xFF; 424 aRec[1] = (iVal>>48) & 0xFF; 425 aRec[2] = (iVal>>40) & 0xFF; 426 aRec[3] = (iVal>>32) & 0xFF; 427 aRec[4] = (iVal>>24) & 0xFF; 428 aRec[5] = (iVal>>16) & 0xFF; 429 aRec[6] = (iVal>> 8) & 0xFF; 430 aRec[7] = (iVal) & 0xFF; 431 } 432 433 /* 434 ** Parse a single table-header from the input. Allocate a new change-group 435 ** object with the results. Return SQLITE_OK if successful, or an error code 436 ** otherwise. 437 */ 438 static int fuzzParseHeader( 439 FuzzChangeset *pParse, /* Changeset parse object */ 440 u8 **ppHdr, /* IN/OUT: Iterator */ 441 u8 *pEnd, /* 1 byte past EOF */ 442 FuzzChangesetGroup **ppGrp /* OUT: New change-group object */ 443 ){ 444 int rc = SQLITE_OK; 445 FuzzChangesetGroup *pGrp; 446 u8 cHdr = (pParse->bPatchset ? 'P' : 'T'); 447 448 assert( pEnd>(*ppHdr) ); 449 pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup)); 450 if( !pGrp ){ 451 rc = SQLITE_NOMEM; 452 }else{ 453 u8 *p = *ppHdr; 454 if( p[0]!=cHdr ){ 455 rc = fuzzCorrupt(); 456 }else{ 457 p++; 458 p += fuzzGetVarint(p, &pGrp->nCol); 459 pGrp->aPK = p; 460 p += pGrp->nCol; 461 pGrp->zTab = (const char*)p; 462 p = &p[strlen(p)+1]; 463 464 if( p>=pEnd ){ 465 rc = fuzzCorrupt(); 466 } 467 } 468 *ppHdr = p; 469 } 470 471 if( rc!=SQLITE_OK ){ 472 fuzzFree(pGrp); 473 pGrp = 0; 474 } 475 476 *ppGrp = pGrp; 477 return rc; 478 } 479 480 /* 481 ** Argument p points to a buffer containing a single changeset-record value. 482 ** This function attempts to determine the size of the value in bytes. If 483 ** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the 484 ** buffer does not contain a valid value, SQLITE_CORRUPT is returned and 485 ** the final value of (*pSz) is undefined. 486 */ 487 static int fuzzChangeSize(u8 *p, int *pSz){ 488 u8 eType = p[0]; 489 switch( eType ){ 490 case 0x00: /* undefined */ 491 case 0x05: /* null */ 492 *pSz = 1; 493 break; 494 495 case 0x01: /* integer */ 496 case 0x02: /* real */ 497 *pSz = 9; 498 break; 499 500 case 0x03: /* text */ 501 case 0x04: { /* blob */ 502 int nTxt; 503 int sz; 504 sz = fuzzGetVarint(&p[1], &nTxt); 505 *pSz = 1 + sz + nTxt; 506 break; 507 } 508 509 default: 510 return fuzzCorrupt(); 511 } 512 return SQLITE_OK; 513 } 514 515 /* 516 ** When this function is called, (*ppRec) points to the start of a 517 ** record in a changeset being parsed. This function adds entries 518 ** to the pParse->apVal[] array for all values and advances (*ppRec) 519 ** to one byte past the end of the record. Argument pEnd points to 520 ** one byte past the end of the input changeset. 521 ** 522 ** Argument bPkOnly is true if the record being parsed is part of 523 ** a DELETE record in a patchset. In this case, all non-primary-key 524 ** fields have been omitted from the record. 525 ** 526 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. 527 */ 528 static int fuzzParseRecord( 529 u8 **ppRec, /* IN/OUT: Iterator */ 530 u8 *pEnd, /* One byte after end of input data */ 531 FuzzChangeset *pParse, /* Changeset parse context */ 532 int bPkOnly /* True if non-PK fields omitted */ 533 ){ 534 int rc = SQLITE_OK; 535 FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1]; 536 int i; 537 u8 *p = *ppRec; 538 539 for(i=0; rc==SQLITE_OK && i<pGrp->nCol; i++){ 540 if( bPkOnly==0 || pGrp->aPK[i] ){ 541 int sz; 542 if( p>=pEnd ) break; 543 if( (pParse->nVal & (pParse->nVal-1))==0 ){ 544 int nNew = pParse->nVal ? pParse->nVal*2 : 4; 545 u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*)); 546 if( apNew==0 ) return SQLITE_NOMEM; 547 pParse->apVal = apNew; 548 } 549 pParse->apVal[pParse->nVal++] = p; 550 rc = fuzzChangeSize(p, &sz); 551 p += sz; 552 } 553 } 554 555 if( rc==SQLITE_OK && i<pGrp->nCol ){ 556 rc = fuzzCorrupt(); 557 } 558 559 *ppRec = p; 560 return rc; 561 } 562 563 /* 564 ** Parse the array of changes starting at (*ppData) and add entries for 565 ** all values to the pParse->apVal[] array. Argument pEnd points to one byte 566 ** past the end of the input changeset. If successful, set (*ppData) to point 567 ** to one byte past the end of the change array and return SQLITE_OK. 568 ** Otherwise, return an SQLite error code. The final value of (*ppData) is 569 ** undefined in this case. 570 */ 571 static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){ 572 u8 cHdr = (pParse->bPatchset ? 'P' : 'T'); 573 FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1]; 574 int rc = SQLITE_OK; 575 u8 *p = *ppData; 576 577 pGrp->aChange = p; 578 while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){ 579 u8 eOp = p[0]; 580 u8 bIndirect = p[1]; 581 582 p += 2; 583 if( eOp==SQLITE_UPDATE ){ 584 pParse->nUpdate++; 585 if( pParse->bPatchset==0 ){ 586 rc = fuzzParseRecord(&p, pEnd, pParse, 0); 587 } 588 }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){ 589 rc = fuzzCorrupt(); 590 } 591 if( rc==SQLITE_OK ){ 592 int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset); 593 rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly); 594 } 595 pGrp->nChange++; 596 pParse->nChange++; 597 } 598 pGrp->szChange = p - pGrp->aChange; 599 600 *ppData = p; 601 return rc; 602 } 603 604 /* 605 ** Parse the changeset stored in buffer pChangeset (nChangeset bytes in 606 ** size). If successful, write the results into (*pParse) and return 607 ** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The 608 ** final state of (*pParse) is undefined in this case. 609 */ 610 static int fuzzParseChangeset( 611 u8 *pChangeset, /* Buffer containing changeset */ 612 int nChangeset, /* Size of buffer in bytes */ 613 FuzzChangeset *pParse /* OUT: Results of parse */ 614 ){ 615 u8 *pEnd = &pChangeset[nChangeset]; 616 u8 *p = pChangeset; 617 int rc = SQLITE_OK; 618 619 memset(pParse, 0, sizeof(FuzzChangeset)); 620 if( nChangeset>0 ){ 621 pParse->bPatchset = (pChangeset[0]=='P'); 622 } 623 624 while( rc==SQLITE_OK && p<pEnd ){ 625 FuzzChangesetGroup *pGrp = 0; 626 627 /* Read a table-header from the changeset */ 628 rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp); 629 assert( (rc==SQLITE_OK)==(pGrp!=0) ); 630 631 /* If the table-header was successfully parsed, add the new change-group 632 ** to the array and parse the associated changes. */ 633 if( rc==SQLITE_OK ){ 634 FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc( 635 pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1) 636 ); 637 if( apNew==0 ){ 638 rc = SQLITE_NOMEM; 639 }else{ 640 apNew[pParse->nGroup] = pGrp; 641 pParse->apGroup = apNew; 642 pParse->nGroup++; 643 } 644 rc = fuzzParseChanges(&p, pEnd, pParse); 645 } 646 } 647 648 return rc; 649 } 650 651 /* 652 ** When this function is called, (*ppRec) points to the first byte of 653 ** a record that is part of change-group pGrp. This function attempts 654 ** to output a human-readable version of the record to stdout and advance 655 ** (*ppRec) to point to the first byte past the end of the record before 656 ** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite 657 ** error code. 658 ** 659 ** If parameter bPkOnly is non-zero, then all non-primary-key fields have 660 ** been omitted from the record. This occurs for records that are part 661 ** of DELETE changes in patchsets. 662 */ 663 static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){ 664 int rc = SQLITE_OK; 665 u8 *p = *ppRec; 666 int i; 667 const char *zPre = " ("; 668 669 for(i=0; i<pGrp->nCol; i++){ 670 if( bPKOnly==0 || pGrp->aPK[i] ){ 671 u8 eType = p++[0]; 672 switch( eType ){ 673 case 0x00: /* undefined */ 674 printf("%sn/a", zPre); 675 break; 676 677 case 0x01: { /* integer */ 678 sqlite3_int64 iVal = 0; 679 iVal = fuzzGetI64(p); 680 printf("%s%lld", zPre, iVal); 681 p += 8; 682 break; 683 } 684 685 case 0x02: { /* real */ 686 sqlite3_int64 iVal = 0; 687 double fVal = 0.0; 688 iVal = fuzzGetI64(p); 689 memcpy(&fVal, &iVal, 8); 690 printf("%s%f", zPre, fVal); 691 p += 8; 692 break; 693 } 694 695 case 0x03: /* text */ 696 case 0x04: { /* blob */ 697 int nTxt; 698 int sz; 699 int i; 700 p += fuzzGetVarint(p, &nTxt); 701 printf("%s%s", zPre, eType==0x03 ? "'" : "X'"); 702 for(i=0; i<nTxt; i++){ 703 if( eType==0x03 ){ 704 printf("%c", p[i]); 705 }else{ 706 char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', 707 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 708 }; 709 printf("%c", aHex[ p[i]>>4 ]); 710 printf("%c", aHex[ p[i] & 0x0F ]); 711 } 712 } 713 printf("'"); 714 p += nTxt; 715 break; 716 } 717 718 case 0x05: /* null */ 719 printf("%sNULL", zPre); 720 break; 721 } 722 zPre = ", "; 723 } 724 } 725 printf(")"); 726 727 *ppRec = p; 728 return rc; 729 } 730 731 /* 732 ** Print a human-readable version of the table-header and all changes in the 733 ** change-group passed as the second argument. 734 */ 735 static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){ 736 int i; 737 u8 *p; 738 739 /* The table header */ 740 printf("TABLE: %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol); 741 for(i=0; i<pGrp->nCol; i++){ 742 printf("%d", (int)pGrp->aPK[i]); 743 } 744 printf("\n"); 745 746 /* The array of changes */ 747 p = pGrp->aChange; 748 for(i=0; i<pGrp->nChange; i++){ 749 u8 eType = p[0]; 750 u8 bIndirect = p[1]; 751 printf("%s (ind=%d):", 752 (eType==SQLITE_INSERT) ? "INSERT" : 753 (eType==SQLITE_DELETE ? "DELETE" : "UPDATE"), 754 bIndirect 755 ); 756 p += 2; 757 758 if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){ 759 fuzzPrintRecord(pGrp, &p, 0); 760 } 761 fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset); 762 printf("\n"); 763 } 764 } 765 766 /* 767 ** Initialize the object passed as the second parameter with details 768 ** of the change that will be attempted (type of change, to which part of the 769 ** changeset it applies etc.). If successful, return SQLITE_OK. Or, if an 770 ** error occurs, return an SQLite error code. 771 ** 772 ** If a negative value is returned, then the selected change would have 773 ** produced a non-well-formed changeset. In this case the caller should 774 ** call this function again. 775 */ 776 static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){ 777 int iSub; 778 779 memset(pChange, 0, sizeof(FuzzChange)); 780 pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1; 781 782 assert( pChange->eType==FUZZ_VALUE_SUB 783 || pChange->eType==FUZZ_VALUE_MOD 784 || pChange->eType==FUZZ_VALUE_RND 785 || pChange->eType==FUZZ_CHANGE_DUP 786 || pChange->eType==FUZZ_CHANGE_DEL 787 || pChange->eType==FUZZ_CHANGE_TYPE 788 || pChange->eType==FUZZ_CHANGE_FIELD 789 || pChange->eType==FUZZ_CHANGE_INDIRECT 790 || pChange->eType==FUZZ_GROUP_DUP 791 || pChange->eType==FUZZ_GROUP_DEL 792 || pChange->eType==FUZZ_GROUP_SWAP 793 || pChange->eType==FUZZ_COLUMN_ADD 794 || pChange->eType==FUZZ_COLUMN_ADDPK 795 || pChange->eType==FUZZ_COLUMN_DEL 796 ); 797 798 pChange->iGroup = fuzzRandomInt(pParse->nGroup); 799 pChange->iChange = fuzzRandomInt(pParse->nChange); 800 if( pChange->eType==FUZZ_CHANGE_FIELD ){ 801 if( pParse->nUpdate==0 ) return -1; 802 pChange->iChange = fuzzRandomInt(pParse->nUpdate); 803 } 804 805 pChange->iDelete = -1; 806 if( pChange->eType==FUZZ_COLUMN_DEL ){ 807 FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup]; 808 int i; 809 pChange->iDelete = fuzzRandomInt(pGrp->nCol); 810 for(i=pGrp->nCol-1; i>=0; i--){ 811 if( pGrp->aPK[i] && pChange->iDelete!=i ) break; 812 } 813 if( i<0 ) return -1; 814 } 815 816 if( pChange->eType==FUZZ_GROUP_SWAP ){ 817 FuzzChangesetGroup *pGrp; 818 int iGrp = pChange->iGroup; 819 if( pParse->nGroup==1 ) return -1; 820 while( iGrp==pChange->iGroup ){ 821 iGrp = fuzzRandomInt(pParse->nGroup); 822 } 823 pGrp = pParse->apGroup[pChange->iGroup]; 824 pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp]; 825 pParse->apGroup[iGrp] = pGrp; 826 } 827 828 if( pChange->eType==FUZZ_VALUE_SUB 829 || pChange->eType==FUZZ_VALUE_MOD 830 || pChange->eType==FUZZ_VALUE_RND 831 ){ 832 iSub = fuzzRandomInt(pParse->nVal); 833 pChange->pSub1 = pParse->apVal[iSub]; 834 if( pChange->eType==FUZZ_VALUE_SUB ){ 835 iSub = fuzzRandomInt(pParse->nVal); 836 pChange->pSub2 = pParse->apVal[iSub]; 837 }else{ 838 pChange->pSub2 = pChange->aSub; 839 } 840 841 if( pChange->eType==FUZZ_VALUE_RND ){ 842 pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1); 843 switch( pChange->aSub[0] ){ 844 case 0x01: { /* integer */ 845 u64 iVal = fuzzRandomU64(); 846 fuzzPutU64(&pChange->aSub[1], iVal); 847 break; 848 } 849 850 case 0x02: { /* real */ 851 u64 iVal1 = fuzzRandomU64(); 852 u64 iVal2 = fuzzRandomU64(); 853 double d = (double)iVal1 / (double)iVal2; 854 memcpy(&iVal1, &d, sizeof(iVal1)); 855 fuzzPutU64(&pChange->aSub[1], iVal1); 856 break; 857 } 858 859 case 0x03: /* text */ 860 case 0x04: { /* blob */ 861 int nByte = fuzzRandomInt(48); 862 pChange->aSub[1] = nByte; 863 fuzzRandomBlob(nByte, &pChange->aSub[2]); 864 if( pChange->aSub[0]==0x03 ){ 865 int i; 866 for(i=0; i<nByte; i++){ 867 pChange->aSub[2+i] &= 0x7F; 868 } 869 } 870 break; 871 } 872 } 873 } 874 if( pChange->eType==FUZZ_VALUE_MOD ){ 875 int sz; 876 int iMod = -1; 877 fuzzChangeSize(pChange->pSub1, &sz); 878 memcpy(pChange->aSub, pChange->pSub1, sz); 879 switch( pChange->aSub[0] ){ 880 case 0x01: 881 case 0x02: 882 iMod = fuzzRandomInt(8) + 1; 883 break; 884 885 case 0x03: /* text */ 886 case 0x04: { /* blob */ 887 int nByte; 888 int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte); 889 if( nByte>0 ){ 890 iMod = fuzzRandomInt(nByte) + iFirst; 891 } 892 break; 893 } 894 } 895 896 if( iMod>=0 ){ 897 u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03))); 898 pChange->aSub[iMod] ^= mask; 899 } 900 } 901 } 902 903 return SQLITE_OK; 904 } 905 906 /* 907 ** Copy a single change from the input to the output changeset, making 908 ** any modifications specified by (*pFuzz). 909 */ 910 static int fuzzCopyChange( 911 FuzzChangeset *pParse, 912 int iGrp, 913 FuzzChange *pFuzz, 914 u8 **pp, u8 **ppOut /* IN/OUT: Input and output pointers */ 915 ){ 916 int bPS = pParse->bPatchset; 917 FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp]; 918 u8 *p = *pp; 919 u8 *pOut = *ppOut; 920 u8 eType = p++[0]; 921 int iRec; 922 int nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1); 923 int iUndef = -1; 924 int nUpdate = 0; 925 926 u8 eNew = eType; 927 if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){ 928 switch( eType ){ 929 case SQLITE_INSERT: 930 eNew = SQLITE_DELETE; 931 break; 932 case SQLITE_DELETE: 933 eNew = SQLITE_UPDATE; 934 break; 935 case SQLITE_UPDATE: 936 eNew = SQLITE_INSERT; 937 break; 938 } 939 } 940 941 if( pFuzz->iCurrent==pFuzz->iChange 942 && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE 943 ){ 944 int sz; 945 int i; 946 int nDef = 0; 947 u8 *pCsr = p+1; 948 for(i=0; i<pGrp->nCol; i++){ 949 if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++; 950 fuzzChangeSize(pCsr, &sz); 951 pCsr += sz; 952 } 953 if( nDef<=1 ) return -1; 954 nDef = fuzzRandomInt(nDef); 955 pCsr = p+1; 956 for(i=0; i<pGrp->nCol; i++){ 957 if( pCsr[0] && pGrp->aPK[i]==0 ){ 958 if( nDef==0 ) iUndef = i; 959 nDef--; 960 } 961 fuzzChangeSize(pCsr, &sz); 962 pCsr += sz; 963 } 964 } 965 966 /* Copy the change type and indirect flag. If the fuzz mode is 967 ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for 968 ** fuzzing, invert the indirect flag. */ 969 *(pOut++) = eNew; 970 if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){ 971 *(pOut++) = !(*(p++)); 972 }else{ 973 *(pOut++) = *(p++); 974 } 975 976 for(iRec=0; iRec<nRec; iRec++){ 977 int i; 978 979 /* Copy the next record from the output to the input. 980 */ 981 for(i=0; i<pGrp->nCol; i++){ 982 int sz; 983 u8 *pCopy = p; 984 985 /* If this is a patchset, and the input is a DELETE, then the only 986 ** fields present are the PK fields. So, if this is not a PK, skip to 987 ** the next column. If the current fuzz is FUZZ_CHANGE_TYPE, then 988 ** write a randomly selected value to the output. */ 989 if( bPS && eType==SQLITE_DELETE && pGrp->aPK[i]==0 ){ 990 if( eType!=eNew ){ 991 assert( eNew==SQLITE_UPDATE ); 992 do { 993 pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)]; 994 }while( pCopy[0]==0x00 ); 995 fuzzChangeSize(pCopy, &sz); 996 memcpy(pOut, pCopy, sz); 997 pOut += sz; 998 } 999 continue; 1000 } 1001 1002 if( p==pFuzz->pSub1 ){ 1003 pCopy = pFuzz->pSub2; 1004 }else if( p==pFuzz->pSub2 ){ 1005 pCopy = pFuzz->pSub1; 1006 }else if( i==iUndef ){ 1007 pCopy = "\0"; 1008 } 1009 1010 if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){ 1011 while( pCopy[0]==0x00 ){ 1012 pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)]; 1013 } 1014 }else if( p[0]==0x00 && pCopy[0]!=0x00 ){ 1015 return -1; 1016 }else{ 1017 if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1; 1018 } 1019 1020 if( (pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete) 1021 && (eNew==eType || eType!=SQLITE_UPDATE || iRec==0) 1022 && (eNew==eType || eNew!=SQLITE_DELETE || !bPS || pGrp->aPK[i]) 1023 ){ 1024 fuzzChangeSize(pCopy, &sz); 1025 memcpy(pOut, pCopy, sz); 1026 pOut += sz; 1027 nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00); 1028 } 1029 1030 fuzzChangeSize(p, &sz); 1031 p += sz; 1032 } 1033 1034 if( iGrp==pFuzz->iGroup ){ 1035 if( pFuzz->eType==FUZZ_COLUMN_ADD ){ 1036 if( !bPS || eType!=SQLITE_DELETE ) *(pOut++) = 0x05; 1037 }else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){ 1038 if( iRec==1 ){ 1039 *(pOut++) = 0x00; 1040 }else{ 1041 u8 *pNew; 1042 int szNew; 1043 do { 1044 pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)]; 1045 }while( pNew[0]==0x00 || pNew[0]==0x05 ); 1046 fuzzChangeSize(pNew, &szNew); 1047 memcpy(pOut, pNew, szNew); 1048 pOut += szNew; 1049 } 1050 } 1051 } 1052 } 1053 1054 if( pFuzz->iCurrent==pFuzz->iChange ){ 1055 if( pFuzz->eType==FUZZ_CHANGE_DUP ){ 1056 int nByte = pOut - (*ppOut); 1057 memcpy(pOut, *ppOut, nByte); 1058 pOut += nByte; 1059 } 1060 1061 if( pFuzz->eType==FUZZ_CHANGE_DEL ){ 1062 pOut = *ppOut; 1063 } 1064 if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){ 1065 int i; 1066 u8 *pCsr = (*ppOut) + 2; 1067 for(i=0; i<pGrp->nCol; i++){ 1068 int sz; 1069 u8 *pCopy = pCsr; 1070 if( pGrp->aPK[i] ) pCopy = "\0"; 1071 fuzzChangeSize(pCopy, &sz); 1072 memcpy(pOut, pCopy, sz); 1073 pOut += sz; 1074 fuzzChangeSize(pCsr, &sz); 1075 pCsr += sz; 1076 } 1077 } 1078 } 1079 1080 /* If a column is being deleted from this group, and this change was an 1081 ** UPDATE, and there are now no non-PK, non-undefined columns in the 1082 ** change, remove it altogether. */ 1083 if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp 1084 && eType==SQLITE_UPDATE && nUpdate==0 1085 ){ 1086 pOut = *ppOut; 1087 } 1088 1089 *pp = p; 1090 *ppOut = pOut; 1091 pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD); 1092 return SQLITE_OK; 1093 } 1094 1095 /* 1096 ** Fuzz the changeset parsed into object pParse and write the results 1097 ** to file zOut on disk. Argument pBuf points to a buffer that is guaranteed 1098 ** to be large enough to hold the fuzzed changeset. 1099 ** 1100 ** Return SQLITE_OK if successful, or an SQLite error code if an error occurs. 1101 */ 1102 static int fuzzDoOneFuzz( 1103 const char *zOut, /* Filename to write modified changeset to */ 1104 u8 *pBuf, /* Buffer to use for modified changeset */ 1105 FuzzChangeset *pParse /* Parse of input changeset */ 1106 ){ 1107 FuzzChange change; 1108 int iGrp; 1109 int rc = -1; 1110 1111 while( rc<0 ){ 1112 u8 *pOut = pBuf; 1113 rc = fuzzSelectChange(pParse, &change); 1114 for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){ 1115 FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp]; 1116 int nTab = strlen(pGrp->zTab) + 1; 1117 int j; 1118 int nRep = 1; 1119 1120 /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to 1121 ** the next group. Unless this is the only group in the changeset - in 1122 ** that case this change cannot be applied. 1123 ** 1124 ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two 1125 ** copies of the group. */ 1126 if( change.iGroup==iGrp ){ 1127 if( change.eType==FUZZ_GROUP_DEL ){ 1128 if( pParse->nGroup==1 ) rc = -1; 1129 continue; 1130 } 1131 else if( change.eType==FUZZ_GROUP_DUP ){ 1132 nRep = 2; 1133 } 1134 } 1135 1136 for(j=0; j<nRep; j++){ 1137 int i; 1138 u8 *pSaved; 1139 u8 *p = pGrp->aChange; 1140 int nCol = pGrp->nCol; 1141 int iPKDel = 0; 1142 if( iGrp==change.iGroup ){ 1143 if( change.eType==FUZZ_COLUMN_ADD 1144 || change.eType==FUZZ_COLUMN_ADDPK 1145 ){ 1146 nCol++; 1147 }else if( change.eType==FUZZ_COLUMN_DEL ){ 1148 nCol--; 1149 iPKDel = pGrp->aPK[change.iDelete]; 1150 } 1151 } 1152 1153 /* Output a table header */ 1154 pOut++[0] = pParse->bPatchset ? 'P' : 'T'; 1155 pOut += fuzzPutVarint(pOut, nCol); 1156 1157 for(i=0; i<pGrp->nCol; i++){ 1158 if( iGrp!=change.iGroup || i!=change.iDelete ){ 1159 u8 v = pGrp->aPK[i]; 1160 if( iPKDel && v>iPKDel ) v--; 1161 *(pOut++) = v; 1162 } 1163 } 1164 if( nCol>pGrp->nCol ){ 1165 if( change.eType==FUZZ_COLUMN_ADD ){ 1166 *(pOut++) = 0x00; 1167 }else{ 1168 u8 max = 0; 1169 for(i=0; i<pGrp->nCol; i++){ 1170 if( pGrp->aPK[i]>max ) max = pGrp->aPK[i]; 1171 } 1172 *(pOut++) = max+1; 1173 } 1174 } 1175 memcpy(pOut, pGrp->zTab, nTab); 1176 pOut += nTab; 1177 1178 /* Output the change array. */ 1179 pSaved = pOut; 1180 for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){ 1181 rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut); 1182 } 1183 if( pOut==pSaved ) rc = -1; 1184 } 1185 } 1186 if( rc==SQLITE_OK ){ 1187 fuzzWriteFile(zOut, pBuf, pOut-pBuf); 1188 } 1189 } 1190 1191 return rc; 1192 } 1193 1194 int main(int argc, char **argv){ 1195 int nRepeat = 0; /* Number of output files */ 1196 int iSeed = 0; /* Value of PRNG seed */ 1197 const char *zInput; /* Name of input file */ 1198 void *pChangeset = 0; /* Input changeset */ 1199 int nChangeset = 0; /* Size of input changeset in bytes */ 1200 int i; /* Current output file */ 1201 FuzzChangeset changeset; /* Partially parsed changeset */ 1202 int rc; 1203 u8 *pBuf = 0; 1204 1205 if( argc!=4 && argc!=2 ) usage(argv[0]); 1206 zInput = argv[1]; 1207 1208 fuzzReadFile(zInput, &nChangeset, &pChangeset); 1209 rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset); 1210 1211 if( rc==SQLITE_OK ){ 1212 if( argc==2 ){ 1213 for(i=0; i<changeset.nGroup; i++){ 1214 fuzzPrintGroup(&changeset, changeset.apGroup[i]); 1215 } 1216 }else{ 1217 pBuf = (u8*)fuzzMalloc(nChangeset*2 + 1024); 1218 if( pBuf==0 ){ 1219 rc = SQLITE_NOMEM; 1220 }else{ 1221 iSeed = atoi(argv[2]); 1222 nRepeat = atoi(argv[3]); 1223 fuzzRandomSeed((unsigned int)iSeed); 1224 for(i=0; rc==SQLITE_OK && i<nRepeat; i++){ 1225 char *zOut = sqlite3_mprintf("%s-%d", zInput, i); 1226 rc = fuzzDoOneFuzz(zOut, pBuf, &changeset); 1227 sqlite3_free(zOut); 1228 } 1229 fuzzFree(pBuf); 1230 } 1231 } 1232 } 1233 1234 if( rc!=SQLITE_OK ){ 1235 fprintf(stderr, "error while processing changeset: %d\n", rc); 1236 } 1237 1238 return rc; 1239 } 1240 1241