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