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