Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix minor issues in the changesetfuzz program. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | changesetfuzz |
Files: | files | file ages | folders |
SHA3-256: |
5c7f024073bc93089f038b5cf122a7a9 |
User & Date: | dan 2018-11-07 20:07:28.570 |
Context
2018-11-07
| ||
20:13 | Merge latest trunk changes into this branch. (check-in: 53cd91d005 user: dan tags: changesetfuzz) | |
20:07 | Fix minor issues in the changesetfuzz program. (check-in: 5c7f024073 user: dan tags: changesetfuzz) | |
17:52 | Update the "changesetfuzz" program to work with patchsets as well as changesets. (check-in: 75b00fbe88 user: dan tags: changesetfuzz) | |
Changes
Changes to ext/session/changesetfuzz.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** ** changesetfuzz INPUT ** changesetfuzz INPUT SEED N ** ** Argument INPUT must be the name of a file containing a binary changeset. ** In the first form above, this program outputs a human-readable version ** of the same changeset. This is chiefly for debugging. ** ** In the second form, arguments SEED and N must both be integers. In this ** case, this program writes N binary changesets to disk. Each output ** changeset is a slightly modified - "fuzzed" - version of the input. ** The output changesets are written to files name "INPUT-$n", where $n is ** an integer between 0 and N-1, inclusive. Output changesets are always ** well-formed. Parameter SEED is used to seed the PRNG - any two | > > > > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ** ** changesetfuzz INPUT ** changesetfuzz INPUT SEED N ** ** Argument INPUT must be the name of a file containing a binary changeset. ** In the first form above, this program outputs a human-readable version ** of the same changeset. This is chiefly for debugging. ** ** As well as changesets, this program can also dump and fuzz patchsets. ** The term "changeset" is used for both patchsets and changesets from this ** point on. ** ** In the second form, arguments SEED and N must both be integers. In this ** case, this program writes N binary changesets to disk. Each output ** changeset is a slightly modified - "fuzzed" - version of the input. ** The output changesets are written to files name "INPUT-$n", where $n is ** an integer between 0 and N-1, inclusive. Output changesets are always ** well-formed. Parameter SEED is used to seed the PRNG - any two |
︙ | ︙ | |||
86 87 88 89 90 91 92 | ** value is appended to all INSERT, DELETE and UPDATE old.* records. ** An "undefined" is appended to new.* UPDATE records. ** ** 14. A column may be removed from a table, provided that it is not the ** only PRIMARY KEY column in the table. In this case the corresponding ** field is removed from all records. In cases where this leaves an UPDATE ** with no non-PK, non-undefined fields, the entire change is removed. | < < < < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | ** value is appended to all INSERT, DELETE and UPDATE old.* records. ** An "undefined" is appended to new.* UPDATE records. ** ** 14. A column may be removed from a table, provided that it is not the ** only PRIMARY KEY column in the table. In this case the corresponding ** field is removed from all records. In cases where this leaves an UPDATE ** with no non-PK, non-undefined fields, the entire change is removed. */ #include "sqlite3.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> |
︙ | ︙ | |||
426 427 428 429 430 431 432 433 | aRec[3] = (iVal>>32) & 0xFF; aRec[4] = (iVal>>24) & 0xFF; aRec[5] = (iVal>>16) & 0xFF; aRec[6] = (iVal>> 8) & 0xFF; aRec[7] = (iVal) & 0xFF; } static int fuzzParseHeader( | > > > > > | | | | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | aRec[3] = (iVal>>32) & 0xFF; aRec[4] = (iVal>>24) & 0xFF; aRec[5] = (iVal>>16) & 0xFF; aRec[6] = (iVal>> 8) & 0xFF; aRec[7] = (iVal) & 0xFF; } /* ** Parse a single table-header from the input. Allocate a new change-group ** object with the results. Return SQLITE_OK if successful, or an error code ** otherwise. */ static int fuzzParseHeader( FuzzChangeset *pParse, /* Changeset parse object */ u8 **ppHdr, /* IN/OUT: Iterator */ u8 *pEnd, /* 1 byte past EOF */ FuzzChangesetGroup **ppGrp /* OUT: New change-group object */ ){ int rc = SQLITE_OK; FuzzChangesetGroup *pGrp; u8 cHdr = (pParse->bPatchset ? 'P' : 'T'); assert( pEnd>(*ppHdr) ); pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup)); |
︙ | ︙ | |||
468 469 470 471 472 473 474 475 476 477 478 479 480 481 | pGrp = 0; } *ppGrp = pGrp; return rc; } static int fuzzChangeSize(u8 *p, int *pSz){ u8 eType = p[0]; switch( eType ){ case 0x00: /* undefined */ case 0x05: /* null */ *pSz = 1; break; | > > > > > > > | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | pGrp = 0; } *ppGrp = pGrp; return rc; } /* ** Argument p points to a buffer containing a single changeset-record value. ** This function attempts to determine the size of the value in bytes. If ** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the ** buffer does not contain a valid value, SQLITE_CORRUPT is returned and ** the final value of (*pSz) is undefined. */ static int fuzzChangeSize(u8 *p, int *pSz){ u8 eType = p[0]; switch( eType ){ case 0x00: /* undefined */ case 0x05: /* null */ *pSz = 1; break; |
︙ | ︙ | |||
496 497 498 499 500 501 502 503 504 505 | default: return fuzzCorrupt(); } return SQLITE_OK; } static int fuzzParseRecord( u8 **ppRec, /* IN/OUT: Iterator */ u8 *pEnd, /* One byte after end of input data */ | > > > > > > > > > > > > > | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | default: return fuzzCorrupt(); } return SQLITE_OK; } /* ** When this function is called, (*ppRec) points to the start of a ** record in a changeset being parsed. This function adds entries ** to the pParse->apVal[] array for all values and advances (*ppRec) ** to one byte past the end of the record. Argument pEnd points to ** one byte past the end of the input changeset. ** ** Argument bPkOnly is true if the record being parsed is part of ** a DELETE record in a patchset. In this case, all non-primary-key ** fields have been omitted from the record. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ static int fuzzParseRecord( u8 **ppRec, /* IN/OUT: Iterator */ u8 *pEnd, /* One byte after end of input data */ FuzzChangeset *pParse, /* Changeset parse context */ int bPkOnly /* True if non-PK fields omitted */ ){ int rc = SQLITE_OK; FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1]; int i; u8 *p = *ppRec; for(i=0; rc==SQLITE_OK && i<pGrp->nCol && p<pEnd; i++){ |
︙ | ︙ | |||
530 531 532 533 534 535 536 537 538 539 540 541 542 543 | rc = fuzzCorrupt(); } *ppRec = p; return rc; } static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){ u8 cHdr = (pParse->bPatchset ? 'P' : 'T'); FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1]; int rc = SQLITE_OK; u8 *p = *ppData; pGrp->aChange = p; | > > > > > > > > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | rc = fuzzCorrupt(); } *ppRec = p; return rc; } /* ** Parse the array of changes starting at (*ppData) and add entries for ** all values to the pParse->apVal[] array. Argument pEnd points to one byte ** past the end of the input changeset. If successful, set (*ppData) to point ** to one byte past the end of the change array and return SQLITE_OK. ** Otherwise, return an SQLite error code. The final value of (*ppData) is ** undefined in this case. */ static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){ u8 cHdr = (pParse->bPatchset ? 'P' : 'T'); FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1]; int rc = SQLITE_OK; u8 *p = *ppData; pGrp->aChange = p; |
︙ | ︙ | |||
563 564 565 566 567 568 569 570 571 572 573 574 575 576 | } pGrp->szChange = p - pGrp->aChange; *ppData = p; return rc; } static int fuzzParseChangeset( u8 *pChangeset, /* Buffer containing changeset */ int nChangeset, /* Size of buffer in bytes */ FuzzChangeset *pParse /* OUT: Results of parse */ ){ u8 *pEnd = &pChangeset[nChangeset]; u8 *p = pChangeset; | > > > > > > | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | } pGrp->szChange = p - pGrp->aChange; *ppData = p; return rc; } /* ** Parse the changeset stored in buffer pChangeset (nChangeset bytes in ** size). If successful, write the results into (*pParse) and return ** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The ** final state of (*pParse) is undefined in this case. */ static int fuzzParseChangeset( u8 *pChangeset, /* Buffer containing changeset */ int nChangeset, /* Size of buffer in bytes */ FuzzChangeset *pParse /* OUT: Results of parse */ ){ u8 *pEnd = &pChangeset[nChangeset]; u8 *p = pChangeset; |
︙ | ︙ | |||
604 605 606 607 608 609 610 611 612 613 614 615 616 617 | rc = fuzzParseChanges(&p, pEnd, pParse); } } return rc; } static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){ int rc = SQLITE_OK; u8 *p = *ppRec; int i; const char *zPre = " ("; for(i=0; i<pGrp->nCol; i++){ | > > > > > > > > > > > > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | rc = fuzzParseChanges(&p, pEnd, pParse); } } return rc; } /* ** When this function is called, (*ppRec) points to the first byte of ** a record that is part of change-group pGrp. This function attempts ** to output a human-readable version of the record to stdout and advance ** (*ppRec) to point to the first byte past the end of the record before ** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite ** error code. ** ** If parameter bPkOnly is non-zero, then all non-primary-key fields have ** been omitted from the record. This occurs for records that are part ** of DELETE changes in patchsets. */ static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){ int rc = SQLITE_OK; u8 *p = *ppRec; int i; const char *zPre = " ("; for(i=0; i<pGrp->nCol; i++){ |
︙ | ︙ | |||
672 673 674 675 676 677 678 | } printf(")"); *ppRec = p; return rc; } | > > > > | | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | } printf(")"); *ppRec = p; return rc; } /* ** Print a human-readable version of the table-header and all changes in the ** change-group passed as the second argument. */ static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){ int i; u8 *p; /* The table header */ printf("TABLE: %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol); for(i=0; i<pGrp->nCol; i++){ printf("%d", (int)pGrp->aPK[i]); |
︙ | ︙ | |||
703 704 705 706 707 708 709 710 711 712 713 714 715 716 | fuzzPrintRecord(pGrp, &p, 0); } fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset); printf("\n"); } } static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){ int iSub; memset(pChange, 0, sizeof(FuzzChange)); pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1; assert( pChange->eType==FUZZ_VALUE_SUB | > > > > > > > > > > | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | fuzzPrintRecord(pGrp, &p, 0); } fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset); printf("\n"); } } /* ** Initialize the object passed as the second parameter with details ** of the change that will be attempted (type of change, to which part of the ** changeset it applies etc.). If successful, return SQLITE_OK. Or, if an ** error occurs, return an SQLite error code. ** ** If a negative value is returned, then the selected change would have ** produced a non-well-formed changeset. In this case the caller should ** call this function again. */ static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){ int iSub; memset(pChange, 0, sizeof(FuzzChange)); pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1; assert( pChange->eType==FUZZ_VALUE_SUB |
︙ | ︙ | |||
833 834 835 836 837 838 839 840 841 842 843 844 845 846 | } } } return SQLITE_OK; } static int fuzzCopyChange( FuzzChangeset *pParse, int iGrp, FuzzChange *pFuzz, u8 **pp, u8 **ppOut /* IN/OUT: Input and output pointers */ ){ int bPS = pParse->bPatchset; | > > > > | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 | } } } return SQLITE_OK; } /* ** Copy a single change from the input to the output changeset, making ** any modifications specified by (*pFuzz). */ static int fuzzCopyChange( FuzzChangeset *pParse, int iGrp, FuzzChange *pFuzz, u8 **pp, u8 **ppOut /* IN/OUT: Input and output pointers */ ){ int bPS = pParse->bPatchset; |
︙ | ︙ | |||
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 | *pp = p; *ppOut = pOut; pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD); return SQLITE_OK; } static int fuzzDoOneFuzz( const char *zOut, /* Filename to write modified changeset to */ u8 *pBuf, /* Buffer to use for modified changeset */ FuzzChangeset *pParse /* Parse of input changeset */ ){ FuzzChange change; int iGrp; | > > > > > > > | 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 | *pp = p; *ppOut = pOut; pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD); return SQLITE_OK; } /* ** Fuzz the changeset parsed into object pParse and write the results ** to file zOut on disk. Argument pBuf points to a buffer that is guaranteed ** to be large enough to hold the fuzzed changeset. ** ** Return SQLITE_OK if successful, or an SQLite error code if an error occurs. */ static int fuzzDoOneFuzz( const char *zOut, /* Filename to write modified changeset to */ u8 *pBuf, /* Buffer to use for modified changeset */ FuzzChangeset *pParse /* Parse of input changeset */ ){ FuzzChange change; int iGrp; |
︙ | ︙ |