From: dan Date: Tue, 21 Feb 2012 10:36:27 +0000 (+0000) Subject: Add further test cases and minor fixes for the fuzzer. X-Git-Tag: version-3.7.11~38 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=766348febe712ba06a6234bc56c0c50c4fd88d84;p=thirdparty%2Fsqlite.git Add further test cases and minor fixes for the fuzzer. FossilOrigin-Name: 583dde93a9176ba4fff85241bafbbe4e5a6cc95f --- diff --git a/manifest b/manifest index c8032d0fb9..b5477ec6ed 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\sinstructions\sin\sthe\sheader\scomment\sof\sthe\sfuzzer\simplementation.\nNew\stest\scases\sfor\sthe\sfuzzer. -D 2012-02-20T22:44:12.628 +C Add\sfurther\stest\scases\sand\sminor\sfixes\sfor\sthe\sfuzzer. +D 2012-02-21T10:36:27.146 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 3f79a373e57c3b92dabf76f40b065e719d31ac34 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -206,7 +206,7 @@ F src/test_config.c a036a69b550ebc477ab9ca2b37269201f888436e F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c 6232d722a4ddb193035aa13a03796bf57d6c12fd -F src/test_fuzzer.c 2c0d96f94fdf7bfc2458dac9835c87b2086fdb67 +F src/test_fuzzer.c d557ab99e9f1c0d8ae7ac639b4c3d4babd279f90 F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99 @@ -504,7 +504,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 -F test/fuzzer1.test 830e260b10213d5dc6aadccc1fc4b0c7fefce7b8 +F test/fuzzer1.test 098fc6dc6edcc8430d8e29a27eae6b9825d35470 F test/hook.test 5f3749de6462a6b87b4209b74adf7df5ac2df639 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/in.test a7b8a0f43da81cd08645b7a710099ffe9ad1126b @@ -989,7 +989,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P 90b7b957f8933047fd2878048dfa3ec4891988b8 -R e208940f645a7d6e8e24937143961be4 -U drh -Z c02d350749266fd28db3de432a6902e8 +P bf1dc7907cf1a5c7e19b04fa1278b2089316c30a +R e5d50c19b0286a351f7b9b6f103c6c32 +U dan +Z 5de28f986fce8d4352f35f6c3b70b1eb diff --git a/manifest.uuid b/manifest.uuid index 6ba7c0f0ec..fd44690269 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bf1dc7907cf1a5c7e19b04fa1278b2089316c30a \ No newline at end of file +583dde93a9176ba4fff85241bafbbe4e5a6cc95f \ No newline at end of file diff --git a/src/test_fuzzer.c b/src/test_fuzzer.c index bfc5b7a2cf..eecea140e0 100644 --- a/src/test_fuzzer.c +++ b/src/test_fuzzer.c @@ -141,6 +141,12 @@ ** of the strings in the second or third column of the fuzzer data table ** is 50 bytes. The maximum cost on a rule is 1000. */ + +/* If SQLITE_DEBUG is not defined, disable assert statements. */ +#ifndef SQLITE_DEBUG +# define NDEBUG +#endif + #include "sqlite3.h" #include #include @@ -289,7 +295,7 @@ static int fuzzerLoadOneRule( fuzzer_rule **ppRule, /* OUT: New rule object */ char **pzErr /* OUT: Error message */ ){ - int iRuleset = sqlite3_column_int(pStmt, 0); + sqlite3_int64 iRuleset = sqlite3_column_int64(pStmt, 0); const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1); const char *zTo = (const char *)sqlite3_column_text(pStmt, 2); int nCost = sqlite3_column_int(pStmt, 3); @@ -311,16 +317,21 @@ static int fuzzerLoadOneRule( } if( nCost<=0 || nCost>FUZZER_MX_COST ){ - *pzErr = sqlite3_mprintf("cost must be between 1 and %d", FUZZER_MX_COST); + *pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d", + p->zClassName, FUZZER_MX_COST + ); rc = SQLITE_ERROR; }else if( nFrom>FUZZER_MX_LENGTH || nTo>FUZZER_MX_LENGTH ){ - *pzErr = sqlite3_mprintf("maximum string length is %d", FUZZER_MX_LENGTH); + *pzErr = sqlite3_mprintf("%s: maximum string length is %d", + p->zClassName, FUZZER_MX_LENGTH + ); rc = SQLITE_ERROR; }else if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){ - *pzErr = sqlite3_mprintf( - "ruleset must be between 0 and %d", FUZZER_MX_RULEID); + *pzErr = sqlite3_mprintf("%s: ruleset must be between 0 and %d", + p->zClassName, FUZZER_MX_RULEID + ); rc = SQLITE_ERROR; }else{ @@ -335,7 +346,7 @@ static int fuzzerLoadOneRule( memcpy(pRule->zTo, zTo, nTo+1); pRule->nTo = nTo; pRule->rCost = nCost; - pRule->iRuleset = iRuleset; + pRule->iRuleset = (int)iRuleset; } } @@ -419,6 +430,59 @@ static int fuzzerLoadRules( return rc; } +/* +** This function converts an SQL quoted string into an unquoted string +** and returns a pointer to a buffer allocated using sqlite3_malloc() +** containing the result. The caller should eventually free this buffer +** using sqlite3_free. +** +** Examples: +** +** "abc" becomes abc +** 'xyz' becomes xyz +** [pqr] becomes pqr +** `mno` becomes mno +*/ +static char *fuzzerDequote(const char *zIn){ + int nIn; /* Size of input string, in bytes */ + char *zOut; /* Output (dequoted) string */ + + nIn = strlen(zIn); + zOut = sqlite3_malloc(nIn+1); + if( zOut ){ + char q = zIn[0]; /* Quote character (if any ) */ + + if( q!='[' && q!= '\'' && q!='"' && q!='`' ){ + memcpy(zOut, zIn, nIn+1); + }else{ + int iOut = 0; /* Index of next byte to write to output */ + int iIn; /* Index of next byte to read from input */ + + if( q=='[' ) q = ']'; + for(iIn=1; iInnCursor==0 ); + while( p->pRule ){ + fuzzer_rule *pRule = p->pRule; + p->pRule = pRule->pNext; + sqlite3_free(pRule); + } + sqlite3_free(p); + return SQLITE_OK; +} /* ** xConnect/xCreate method for the fuzzer module. Arguments are: @@ -453,15 +517,24 @@ static int fuzzerConnect( if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ + char *zTab; /* Dequoted name of fuzzer data table */ + memset(pNew, 0, sizeof(*pNew)); pNew->zClassName = (char*)&pNew[1]; memcpy(pNew->zClassName, zModule, nModule+1); - rc = fuzzerLoadRules(db, pNew, zDb, argv[3], pzErr); + zTab = fuzzerDequote(argv[3]); + if( zTab==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = fuzzerLoadRules(db, pNew, zDb, zTab, pzErr); + sqlite3_free(zTab); + } + if( rc==SQLITE_OK ){ - sqlite3_declare_vtab(db, "CREATE TABLE x(word, distance,ruleset)"); + sqlite3_declare_vtab(db, "CREATE TABLE x(word, distance, ruleset)"); }else{ - sqlite3_free(pNew); + fuzzerDisconnect((sqlite3_vtab *)pNew); pNew = 0; } } @@ -470,22 +543,6 @@ static int fuzzerConnect( *ppVtab = (sqlite3_vtab *)pNew; return rc; } -/* Note that for this virtual table, the xCreate and xConnect -** methods are identical. */ - -static int fuzzerDisconnect(sqlite3_vtab *pVtab){ - fuzzer_vtab *p = (fuzzer_vtab*)pVtab; - assert( p->nCursor==0 ); - while( p->pRule ){ - fuzzer_rule *pRule = p->pRule; - p->pRule = pRule->pNext; - sqlite3_free(pRule); - } - sqlite3_free(p); - return SQLITE_OK; -} -/* The xDisconnect and xDestroy methods are also the same */ - /* ** Open a new fuzzer cursor. diff --git a/test/fuzzer1.test b/test/fuzzer1.test index 8e8d581a77..89662c86fe 100644 --- a/test/fuzzer1.test +++ b/test/fuzzer1.test @@ -22,6 +22,8 @@ ifcapable !vtab { return } +set ::testprefix fuzzer1 + register_fuzzer_module db @@ -1538,4 +1540,182 @@ do_execsql_test fuzzer1-4.1 { SELECT word FROM f3 WHERE word MATCH 'ax' } {ax ay} +#------------------------------------------------------------------------- +# +# 1.5.1 - Check things work with a fuzzer data table name that requires +# quoting. Also that NULL entries in the "from" column of the +# data table are treated as zero length strings (''). +# +# 1.5.2 - Check that no-op rules (i.e. C->C) are ignored. Test NULL in +# the "to" column of a fuzzer data table. +# +# 1.5.3 - Test out-of-range values for the cost field of the data table. +# +# 1.5.4 - Test out-of-range values for the string fields of the data table. +# +# 1.5.5 - Test out-of-range values for the ruleset field of the data table. +# +do_execsql_test 5.1 { + CREATE TABLE "fuzzer [x] rules table"(a, b, c, d); + INSERT INTO "fuzzer [x] rules table" VALUES(0, NULL, 'abc', 10); + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); + SELECT word, distance FROM x WHERE word MATCH '123' LIMIT 4; +} {123 0 abc123 10 1abc23 10 12abc3 10} + +do_execsql_test 5.2 { + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES(0, 'x', NULL, 20); + INSERT INTO "fuzzer [x] rules table" VALUES(0, NULL, NULL, 10); + INSERT INTO "fuzzer [x] rules table" VALUES(0, 'x', 'x', 10); + + DROP TABLE x; + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); + + SELECT word, distance FROM x WHERE word MATCH 'xx'; +} {xx 0 x 20 {} 40} + +do_execsql_test 5.3.1 { + DROP TABLE IF EXISTS x; + INSERT INTO "fuzzer [x] rules table" VALUES(0, 'c', 'd', 1001); +} +do_catchsql_test 5.3.2 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: cost must be between 1 and 1000}} + +do_execsql_test 5.3.3 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES(0, 'd', 'c', 0); +} +do_catchsql_test 5.3.4 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: cost must be between 1 and 1000}} + +do_execsql_test 5.3.5 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES(0, 'd', 'c', -20); +} +do_catchsql_test 5.3.6 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: cost must be between 1 and 1000}} + +do_execsql_test 5.4.1 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES( + 0, 'x', '12345678901234567890123456789012345678901234567890', 2 + ); + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); + SELECT word FROM x WHERE word MATCH 'x'; +} {x 12345678901234567890123456789012345678901234567890} + +do_execsql_test 5.4.2 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES( + 0, 'x', '123456789012345678901234567890123456789012345678901', 2 + ); +} +do_catchsql_test 5.4.3 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: maximum string length is 50}} + +do_execsql_test 5.4.4 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES( + 0, '123456789012345678901234567890123456789012345678901', 'x', 2 + ); +} +do_catchsql_test 5.4.5 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: maximum string length is 50}} + +do_execsql_test 5.5.1 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES(-1, 'x', 'y', 2); +} +do_catchsql_test 5.5.2 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: ruleset must be between 0 and 2147483647}} + +do_execsql_test 5.5.3 { + DROP TABLE IF EXISTS x; + DELETE FROM "fuzzer [x] rules table"; + INSERT INTO "fuzzer [x] rules table" VALUES((1<<32)+100, 'x', 'y', 2); +} +do_catchsql_test 5.5.4 { + CREATE VIRTUAL TABLE x USING fuzzer('fuzzer [x] rules table'); +} {1 {fuzzer: ruleset must be between 0 and 2147483647}} + +#------------------------------------------------------------------------- +# This test uses a fuzzer table with many rules. There is one rule to +# map each possible two character string, where characters are lower-case +# letters used in the English language, to all other possible two character +# strings. In total, (26^4)-(26^2) mappings (the subtracted term represents +# the no-op mappings discarded automatically by the fuzzer). +# +# +do_execsql_test 6.1.1 { + DROP TABLE IF EXISTS x1; + DROP TABLE IF EXISTS x1_rules; + CREATE TABLE x1_rules(ruleset, cFrom, cTo, cost); +} +puts "This test is slow - perhaps around 7 seconds on an average pc" +do_test 6.1.2 { + set LETTERS {a b c d e f g h i j k l m n o p q r s t u v w x y z} + set cost 1 + db transaction { + foreach c1 $LETTERS { + foreach c2 $LETTERS { + foreach c3 $LETTERS { + foreach c4 $LETTERS { + db eval {INSERT INTO x1_rules VALUES(0, $c1||$c2, $c3||$c4, $cost)} + set cost [expr ($cost%1000) + 1] + } + } + } + } + db eval {UPDATE x1_rules SET cost = 20 WHERE cost<20 AND cFrom!='xx'} + } +} {} + +do_execsql_test 6.2 { + SELECT count(*) FROM x1_rules WHERE cTo!=cFrom; +} [expr 26*26*26*26 - 26*26] + +do_execsql_test 6.2.1 { + CREATE VIRTUAL TABLE x1 USING fuzzer(x1_rules); + SELECT word FROM x1 WHERE word MATCH 'xx' LIMIT 10; +} {xx hw hx hy hz ia ib ic id ie} +do_execsql_test 6.2.2 { + SELECT cTo FROM x1_rules WHERE cFrom='xx' + ORDER BY cost asc, rowid asc LIMIT 9; +} {hw hx hy hz ia ib ic id ie} + + +#------------------------------------------------------------------------- +# Test using different types of quotes with CREATE VIRTUAL TABLE +# arguments. +# +do_execsql_test 7.1 { + CREATE TABLE [x2 "rules] (a, b, c, d); + INSERT INTO [x2 "rules] VALUES(0, 'a', 'b', 5); +} +foreach {tn sql} { + 1 { CREATE VIRTUAL TABLE x2 USING fuzzer( [x2 "rules] ) } + 2 { CREATE VIRTUAL TABLE x2 USING fuzzer( "x2 ""rules" ) } + 3 { CREATE VIRTUAL TABLE x2 USING fuzzer( 'x2 "rules' ) } + 4 { CREATE VIRTUAL TABLE x2 USING fuzzer( `x2 "rules` ) } +} { + do_execsql_test 7.2.$tn.1 { DROP TABLE IF EXISTS x2 } + do_execsql_test 7.2.$tn.2 $sql + do_execsql_test 7.2.$tn.3 { + SELECT word FROM x2 WHERE word MATCH 'aaa' + } {aaa baa aba aab bab abb bba bbb} +} + finish_test +