Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Prevent the fuzzer from ever returning a string longer than 100 bytes. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
969095ca3067d60f4d3a0a4ad419541c |
User & Date: | dan 2012-02-21 18:00:20.124 |
Context
2012-02-21
| ||
18:35 | Avoid redefining NDEBUG if the fuzzer is included in an amalagmated source file. (check-in: f8ac826f95 user: drh tags: trunk) | |
18:00 | Prevent the fuzzer from ever returning a string longer than 100 bytes. (check-in: 969095ca30 user: dan tags: trunk) | |
14:11 | Further fuzzer test cases. Fix a case in the fuzzer where an error code was being dropped. (check-in: 8b77d3953f user: dan tags: trunk) | |
Changes
Changes to src/test_fuzzer.c.
︙ | ︙ | |||
176 177 178 179 180 181 182 | typedef int fuzzer_cost; typedef signed char fuzzer_len; typedef int fuzzer_ruleid; /* ** Limits */ | | > | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | typedef int fuzzer_cost; typedef signed char fuzzer_len; typedef int fuzzer_ruleid; /* ** Limits */ #define FUZZER_MX_LENGTH 50 /* Maximum length of a rule string */ #define FUZZER_MX_RULEID 2147483647 /* Maximum rule ID */ #define FUZZER_MX_COST 1000 /* Maximum single-rule cost */ #define FUZZER_MX_OUTPUT_LENGTH 100 /* Maximum length of an output string */ /* ** Each transformation rule is stored as an instance of this object. ** All rules are kept on a linked list sorted by rCost. */ struct fuzzer_rule { |
︙ | ︙ | |||
608 609 610 611 612 613 614 | */ static int fuzzerRender( fuzzer_stem *pStem, /* The stem to be rendered */ char **pzBuf, /* Write results into this buffer. realloc if needed */ int *pnBuf /* Size of the buffer */ ){ const fuzzer_rule *pRule = pStem->pRule; | | | > > | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | */ static int fuzzerRender( fuzzer_stem *pStem, /* The stem to be rendered */ char **pzBuf, /* Write results into this buffer. realloc if needed */ int *pnBuf /* Size of the buffer */ ){ const fuzzer_rule *pRule = pStem->pRule; int n; /* Size of output term without nul-term */ char *z; /* Buffer to assemble output term in */ n = pStem->nBasis + pRule->nTo - pRule->nFrom; if( (*pnBuf)<n+1 ){ (*pzBuf) = sqlite3_realloc((*pzBuf), n+100); if( (*pzBuf)==0 ) return SQLITE_NOMEM; (*pnBuf) = n+100; } n = pStem->n; z = *pzBuf; if( n<0 ){ memcpy(z, pStem->zBasis, pStem->nBasis+1); }else{ memcpy(z, pStem->zBasis, n); memcpy(&z[n], pRule->zTo, pRule->nTo); memcpy(&z[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom], pStem->nBasis-n-pRule->nFrom+1); } assert( z[pStem->nBasis + pRule->nTo - pRule->nFrom]==0 ); return SQLITE_OK; } /* ** Compute a hash on zBasis. */ static unsigned int fuzzerHash(const char *z){ |
︙ | ︙ | |||
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | h = fuzzerHash(pCur->zBuf); pLookup = pCur->apHash[h]; while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){ pLookup = pLookup->pHash; } return pLookup!=0; } /* ** Advance a fuzzer_stem to its next value. Return 0 if there are ** no more values that can be generated by this fuzzer_stem. Return ** -1 on a memory allocation failure. */ static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){ const fuzzer_rule *pRule; | > > > > > > > > > > > > > > > > > > > < | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | h = fuzzerHash(pCur->zBuf); pLookup = pCur->apHash[h]; while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){ pLookup = pLookup->pHash; } return pLookup!=0; } /* ** If argument pRule is NULL, this function returns false. ** ** Otherwise, it returns true if rule pRule should be skipped. A rule ** should be skipped if it does not belong to rule-set iRuleset, or if ** applying it to stem pStem would create a string longer than ** FUZZER_MX_OUTPUT_LENGTH bytes. */ static int fuzzerSkipRule( const fuzzer_rule *pRule, /* Determine whether or not to skip this */ fuzzer_stem *pStem, /* Stem rule may be applied to */ int iRuleset /* Rule-set used by the current query */ ){ return pRule && ( (pRule->iRuleset!=iRuleset) || (pStem->nBasis + pRule->nTo - pRule->nFrom)>FUZZER_MX_OUTPUT_LENGTH ); } /* ** Advance a fuzzer_stem to its next value. Return 0 if there are ** no more values that can be generated by this fuzzer_stem. Return ** -1 on a memory allocation failure. */ static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){ const fuzzer_rule *pRule; while( (pRule = pStem->pRule)!=0 ){ assert( pRule==&pCur->nullRule || pRule->iRuleset==pCur->iRuleset ); while( pStem->n < pStem->nBasis - pRule->nFrom ){ pStem->n++; if( pRule->nFrom==0 || memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0 ){ /* Found a rewrite case. Make sure it is not a duplicate */ int rc = fuzzerSeen(pCur, pStem); if( rc<0 ) return -1; if( rc==0 ){ fuzzerCost(pStem); return 1; } } } pStem->n = -1; do{ pRule = pRule->pNext; }while( fuzzerSkipRule(pRule, pStem, pCur->iRuleset) ); pStem->pRule = pRule; if( pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0; } return 0; } /* |
︙ | ︙ | |||
852 853 854 855 856 857 858 | pNew = sqlite3_malloc( sizeof(*pNew) + strlen(zWord) + 1 ); if( pNew==0 ) return 0; memset(pNew, 0, sizeof(*pNew)); pNew->zBasis = (char*)&pNew[1]; pNew->nBasis = strlen(zWord); memcpy(pNew->zBasis, zWord, pNew->nBasis+1); pRule = pCur->pVtab->pRule; | | | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 | pNew = sqlite3_malloc( sizeof(*pNew) + strlen(zWord) + 1 ); if( pNew==0 ) return 0; memset(pNew, 0, sizeof(*pNew)); pNew->zBasis = (char*)&pNew[1]; pNew->nBasis = strlen(zWord); memcpy(pNew->zBasis, zWord, pNew->nBasis+1); pRule = pCur->pVtab->pRule; while( fuzzerSkipRule(pRule, pNew, pCur->iRuleset) ){ pRule = pRule->pNext; } pNew->pRule = pRule; pNew->n = -1; pNew->rBaseCost = pNew->rCostX = rBaseCost; h = fuzzerHash(pNew->zBasis); pNew->pHash = pCur->apHash[h]; |
︙ | ︙ | |||
902 903 904 905 906 907 908 | } } /* Adjust the priority queue so that the first element of the ** stem list is the next lowest cost word. */ while( (pStem = pCur->pStem)!=0 ){ | | > > > | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | } } /* Adjust the priority queue so that the first element of the ** stem list is the next lowest cost word. */ while( (pStem = pCur->pStem)!=0 ){ int res = fuzzerAdvance(pCur, pStem); if( res<0 ){ return SQLITE_NOMEM; }else if( res>0 ){ pCur->pStem = 0; pStem = fuzzerInsert(pCur, pStem); if( (rc = fuzzerSeen(pCur, pStem))!=0 ){ if( rc<0 ) return SQLITE_NOMEM; continue; } return SQLITE_OK; /* New word found */ |
︙ | ︙ | |||
940 941 942 943 944 945 946 | */ static int fuzzerFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor; | | < < < > > > > > > > > | | > | > > | 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 | */ static int fuzzerFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor; const char *zWord = ""; fuzzer_stem *pStem; int idx; fuzzerClearCursor(pCur, 1); pCur->rLimit = 2147483647; idx = 0; if( idxNum & 1 ){ zWord = (const char*)sqlite3_value_text(argv[0]); idx++; } if( idxNum & 2 ){ pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[idx]); idx++; } if( idxNum & 4 ){ pCur->iRuleset = (fuzzer_cost)sqlite3_value_int(argv[idx]); idx++; } pCur->nullRule.pNext = pCur->pVtab->pRule; pCur->nullRule.rCost = 0; pCur->nullRule.nFrom = 0; pCur->nullRule.nTo = 0; pCur->nullRule.zFrom = ""; pCur->iRowid = 1; assert( pCur->pStem==0 ); /* If the query term is longer than FUZZER_MX_OUTPUT_LENGTH bytes, this ** query will return zero rows. */ if( strlen(zWord)<FUZZER_MX_OUTPUT_LENGTH ){ pCur->pStem = pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0); if( pStem==0 ) return SQLITE_NOMEM; pStem->pRule = &pCur->nullRule; pStem->n = pStem->nBasis; }else{ pCur->rLimit = 0; } return SQLITE_OK; } /* ** Only the word and distance columns have values. All other columns ** return NULL */ |
︙ | ︙ | |||
1152 1153 1154 1155 1156 1157 1158 | Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } | | | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 | Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } getDbPointer(interp, Tcl_GetString(objv[1]), &db); fuzzer_register(db); return TCL_OK; } /* ** Register commands with the TCL interpreter. |
︙ | ︙ |
Changes to test/fuzzer1.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ifcapable !vtab { finish_test return } set ::testprefix fuzzer1 | > > | | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | ifcapable !vtab { finish_test return } set ::testprefix fuzzer1 # Test of test code. Only here to make the coverage metric better. do_test 0.1 { list [catch { register_fuzzer_module a b c } msg] $msg } {1 {wrong # args: should be "register_fuzzer_module DB"}} register_fuzzer_module db # Check configuration errors. # do_catchsql_test fuzzer1-1.1 { CREATE VIRTUAL TABLE f USING fuzzer; } {1 {fuzzer: wrong number of CREATE VIRTUAL TABLE arguments}} |
︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 | SELECT word FROM x3 WHERE ruleset=1 AND word MATCH 'a' ORDER BY word ASC; } {a t u v} do_execsql_test 8.2.14 { SELECT word FROM x3 WHERE ruleset=1 AND word MATCH 'a' ORDER BY word DESC; } {v u t a} | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 | SELECT word FROM x3 WHERE ruleset=1 AND word MATCH 'a' ORDER BY word ASC; } {a t u v} do_execsql_test 8.2.14 { SELECT word FROM x3 WHERE ruleset=1 AND word MATCH 'a' ORDER BY word DESC; } {v u t a} #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE x4_rules(a, b, c, d); INSERT INTO x4_rules VALUES(0, 'a', 'b', 10); INSERT INTO x4_rules VALUES(0, 'a', 'c', 11); INSERT INTO x4_rules VALUES(0, 'bx', 'zz', 20); INSERT INTO x4_rules VALUES(0, 'cx', 'yy', 15); INSERT INTO x4_rules VALUES(0, 'zz', '!!', 50); CREATE VIRTUAL TABLE x4 USING fuzzer(x4_rules); } do_execsql_test 9.2 { SELECT word, distance FROM x4 WHERE word MATCH 'ax'; } {ax 0 bx 10 cx 11 yy 26 zz 30 !! 80} do_execsql_test 10.1 { CREATE TABLE x5_rules(a, b, c, d); CREATE VIRTUAL TABLE x5 USING fuzzer(x5_rules); } do_execsql_test 10.2 { SELECT word, distance FROM x5 WHERE word MATCH 'aaaaaaaaaXaaaaaaaaaXaaaaaaaaaXaaaaaaaaaXaaaaaaaaa' || 'aaaaaaaaaXaaaaaaaaaXaaaaaaaaaXaaaaaaaaaXaaaaaaaaa' || 'aaaaaaaaaXaaaaaaaaaXaaaaaaaaaXaaaaaaaaaXaaaaaaaaa' } {} do_execsql_test 10.3 { INSERT INTO x5_rules VALUES(0, 'a', '0.1.2.3.4.5.6.7.8.9.a', 1); DROP TABLE x5; CREATE VIRTUAL TABLE x5 USING fuzzer(x5_rules); SELECT length(word) FROM x5 WHERE word MATCH 'a' LIMIT 50; } {1 21 41 61 81} finish_test |
Changes to test/fuzzerfault.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 | CREATE TABLE x1_rules(ruleset, cFrom, cTo, cost); INSERT INTO x1_rules VALUES(0, 'a', 'b', 1); INSERT INTO x1_rules VALUES(0, 'a', 'c', 2); INSERT INTO x1_rules VALUES(0, 'a', 'd', 3); } faultsim_save_and_close } {} | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | CREATE TABLE x1_rules(ruleset, cFrom, cTo, cost); INSERT INTO x1_rules VALUES(0, 'a', 'b', 1); INSERT INTO x1_rules VALUES(0, 'a', 'c', 2); INSERT INTO x1_rules VALUES(0, 'a', 'd', 3); } faultsim_save_and_close } {} do_faultsim_test 1 -prep { faultsim_restore_and_reopen register_fuzzer_module db } -body { execsql { CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); SELECT word FROM x1 WHERE word MATCH 'xax'; } } -test { faultsim_test_result {0 {xax xbx xcx xdx}} \ {1 {vtable constructor failed: x1}} } do_test 2-pre1 { faultsim_delete_and_reopen register_fuzzer_module db execsql { CREATE TABLE x2_rules(ruleset, cFrom, cTo, cost); INSERT INTO x2_rules VALUES(0, 'a', 'x', 1); INSERT INTO x2_rules VALUES(0, 'b', 'x', 2); INSERT INTO x2_rules VALUES(0, 'c', 'x', 3); CREATE VIRTUAL TABLE x2 USING fuzzer(x2_rules); } faultsim_save_and_close } {} do_faultsim_test 2 -prep { faultsim_restore_and_reopen register_fuzzer_module db } -body { execsql { SELECT count(*) FROM x2 WHERE word MATCH 'abc'; } } -test { faultsim_test_result {0 8} {1 {vtable constructor failed: x2}} } do_test 3-pre1 { faultsim_delete_and_reopen execsql { CREATE TABLE x1_rules(ruleset, cFrom, cTo, cost); INSERT INTO x1_rules VALUES(0, 'a', '123456789012345678901234567890a1234567890123456789', 10 ); } faultsim_save_and_close } {} do_faultsim_test 3 -prep { faultsim_restore_and_reopen register_fuzzer_module db } -body { execsql { CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); SELECT count(*) FROM (SELECT * FROM x1 WHERE word MATCH 'a' LIMIT 2); } } -test { faultsim_test_result {0 2} {1 {vtable constructor failed: x1}} } finish_test |