From: drh Date: Sat, 26 Mar 2011 15:05:27 +0000 (+0000) Subject: Skeleton code for the word-fuzzer virtual table. X-Git-Tag: version-3.7.6~60^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=326a67d0e8da09067c46001edb6808ba5fc3b02c;p=thirdparty%2Fsqlite.git Skeleton code for the word-fuzzer virtual table. FossilOrigin-Name: ea3a4ee136ff6699c3099178f0efaa8bb517715f --- diff --git a/Makefile.in b/Makefile.in index 2c5490265d..2ee36dec43 100644 --- a/Makefile.in +++ b/Makefile.in @@ -356,6 +356,7 @@ TESTSRC = \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ + $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ diff --git a/main.mk b/main.mk index 29374c546f..cfea9b590f 100644 --- a/main.mk +++ b/main.mk @@ -237,6 +237,7 @@ TESTSRC = \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ + $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ diff --git a/manifest b/manifest index d485703eda..44205160e6 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,10 @@ -C Minor\schange\sto\ssqlite3Utf8Read()\sto\smake\sconsistent\swith\sREAD_UTF8()\susage\sand\savoid\simplementation\sdefined\susages\sof\s<<.\s\s\nAdded\ssome\sadditional\sUTF-8\stest\scases. -D 2011-03-24T17:43:18.990 +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +C Skeleton\scode\sfor\sthe\sword-fuzzer\svirtual\stable. +D 2011-03-26T15:05:27.457 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f +F Makefile.in 6c96e694f446500449f683070b906de9fce17b88 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 @@ -101,7 +104,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F main.mk 54190fab7cdba523e311c274c95ea480f32abfb5 +F main.mk a767e12162f02719fa94697a6ff0c8b51bcd62a6 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -184,7 +187,7 @@ F src/sqliteInt.h f8f1d00a22c98fd3f2fbc94da74eeb880879f89f F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e -F src/tclsqlite.c 879bf8a23d99fc0e99d9177fe1b48896bc796d65 +F src/tclsqlite.c 44979405594d33c55ec5ef8e82533d3b4133e455 F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc @@ -202,6 +205,7 @@ F src/test_config.c 62f0f8f934b1d5c7e4cd4f506ae453a1117b47d7 F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5 +F src/test_fuzzer.c b09d2f47bc3ae1485100b323479c5d785d4f6e4b F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2 F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99 @@ -475,6 +479,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c +F test/fuzzer1.test 29120e10821e2d04887b39c6c1ae4ddcbd2bb7f6 F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d @@ -916,7 +921,18 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 69fe0c873d702ef1d781453ee6ac2b1fb77fce48 -R 3655844fccb71eb3fdafa07a1f475145 -U shaneh -Z 4c379d73c236b4115e9dab5017415240 +P 7173b3929fae4e678223b0e978a2da7fa50a9005 +R 88772465d0029c6e2564e31a16d9e60f +T *bgcolor * #b0b28e +T *branch * word-fuzzer +T *sym-word-fuzzer * +T -sym-trunk * +U drh +Z 56aa191286824371992372fc6a5d252f +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQFNjgC7oxKgR168RlERAutAAJ0V6j75yMfG5zTEYnDlvPG7yBJM5ACfSqKu +yFIOeN9GMM2kCskHQ5jGilY= +=IVMz +-----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 44925bdb50..a0f61071e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7173b3929fae4e678223b0e978a2da7fa50a9005 \ No newline at end of file +ea3a4ee136ff6699c3099178f0efaa8bb517715f \ No newline at end of file diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 57f38d78d1..e77a1ee919 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3581,6 +3581,7 @@ static void init_all(Tcl_Interp *interp){ extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); + extern int Sqlitetestfuzzer_Init(Tcl_Interp*); #ifdef SQLITE_ENABLE_ZIPVFS extern int Zipvfs_Init(Tcl_Interp*); @@ -3618,6 +3619,7 @@ static void init_all(Tcl_Interp *interp){ Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); + Sqlitetestfuzzer_Init(interp); Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0); diff --git a/src/test_fuzzer.c b/src/test_fuzzer.c new file mode 100644 index 0000000000..406c1a264e --- /dev/null +++ b/src/test_fuzzer.c @@ -0,0 +1,407 @@ +/* +** 2011 March 24 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** Code for demonstartion virtual table that generates variations +** on an input word at increasing edit distances from the original. +*/ +#include "sqlite3.h" +#include +#include +#include + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +/* +** Forward declaration of objects used by this implementation +*/ +typedef struct fuzzer_vtab fuzzer_vtab; +typedef struct fuzzer_cursor fuzzer_cursor; +typedef struct fuzzer_rule fuzzer_rule; +typedef struct fuzzer_seen fuzzer_seen; +typedef struct fuzzer_stem fuzzer_stem; + + +/* +** 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 { + fuzzer_rule *pNext; /* Next rule in order of increasing rCost */ + float rCost; /* Cost of this transformation */ + char *zFrom; /* Transform from */ + char zTo[4]; /* Transform to (extra space appended) */ +}; + +/* +** When generating fuzzed words, we have to remember all previously +** generated terms in order to suppress duplicates. Each previously +** generated term is an instance of the following structure. +*/ +struct fuzzer_seen { + fuzzer_seen *pNext; /* Next with the same hash */ + char zWord[4]; /* The generated term. */ +}; + +/* +** A stem object is used to generate variants. +*/ +struct fuzzer_stem { + char *zBasis; /* Word being fuzzed */ + fuzzer_rule *pRule; /* Next rule to apply */ + int n; /* Apply rule at this character offset */ + float rBaseCost; /* Base cost of getting to zBasis */ + float rCost; /* rBaseCost + cost of applying pRule at n */ + fuzzer_stem *pNext; /* Next stem in rCost order */ +}; + +/* +** A fuzzer virtual-table object +*/ +struct fuzzer_vtab { + sqlite3_vtab base; /* Base class - must be first */ + char *zClassName; /* Name of this class. Default: "fuzzer" */ + fuzzer_rule *pRule; /* All active rules in this fuzzer */ + fuzzer_rule *pNewRule; /* New rules to add when last cursor expires */ + int nCursor; /* Number of active cursors */ +}; + +/* A fuzzer cursor object */ +struct fuzzer_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + float rMax; /* Maximum cost of any term */ + fuzzer_stem *pStem; /* Sorted list of stems for generating new terms */ + int nSeen; /* Number of terms already generated */ + int nHash; /* Number of slots in apHash */ + fuzzer_seen **apHash; /* Hash table of previously generated terms */ +}; + +/* Methods for the fuzzer module */ +static int fuzzerConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + fuzzer_vtab *pNew; + char *zSql; + int n; + if( strcmp(argv[1],"temp")!=0 ){ + *pzErr = sqlite3_mprintf("%s virtual tables must be TEMP", argv[0]); + return SQLITE_ERROR; + } + n = strlen(argv[0]) + 1; + pNew = sqlite3_malloc( sizeof(*pNew) + n ); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->zClassName = (char*)&pNew[1]; + memcpy(pNew->zClassName, argv[0], n); + zSql = sqlite3_mprintf( + "CREATE TABLE x(word, distance, cFrom, cTo, cost, \"%w\" HIDDEN)", + argv[2] + ); + sqlite3_declare_vtab(db, zSql); + sqlite3_free(zSql); + memset(pNew, 0, sizeof(*pNew)); + *ppVtab = &pNew->base; + return SQLITE_OK; +} +/* 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 ); + do{ + while( p->pRule ){ + fuzzer_rule *pRule = p->pRule; + p->pRule = pRule->pNext; + sqlite3_free(pRule); + } + p->pRule = p->pNewRule; + p->pNewRule = 0; + }while( p->pRule ); + sqlite3_free(p); + return SQLITE_OK; +} +/* The xDisconnect and xDestroy methods are also the same */ + +/* +** The two input rule lists are both sorted in order of increasing +** cost. Merge them together into a single list, sorted by cost, and +** return a pointer to the head of that list. +*/ +static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){ + fuzzer_rule head; + fuzzer_rule *pTail; + + pTail = &head; + while( pA && pB ){ + if( pA->rCost<=pB->rCost ){ + pTail->pNext = pA; + pTail = pA; + pA = pA->pNext; + }else{ + pTail->pNext = pB; + pTail = pB; + pB = pB->pNext; + } + } + if( pA==0 ){ + pTail->pNext = pB; + }else{ + pTail->pNext = pA; + } + return head.pNext; +} + + +/* +** Open a new fuzzer cursor. +*/ +static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ + fuzzer_vtab *p = (fuzzer_vtab*)pVTab; + fuzzer_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + if( p->nCursor==0 && p->pNewRule ){ + unsigned int i; + fuzzer_rule *pX; + fuzzer_rule *a[15]; + for(i=0; ipNewRule)!=0 ){ + p->pNewRule = pX->pNext; + pX->pNext = 0; + for(i=0; a[i] && ipRule = fuzzerMergeRules(p->pRule, pX); + } + + return SQLITE_OK; +} + +/* +** Close a fuzzer cursor. +*/ +static int fuzzerClose(sqlite3_vtab_cursor *cur){ + fuzzer_cursor *pCur = (fuzzer_cursor *)cur; + int i; + for(i=0; inHash; i++){ + fuzzer_seen *pSeen = pCur->apHash[i]; + while( pSeen ){ + fuzzer_seen *pNext = pSeen->pNext; + sqlite3_free(pSeen); + pSeen = pNext; + } + } + sqlite3_free(pCur->apHash); + while( pCur->pStem ){ + fuzzer_stem *pStem = pCur->pStem; + pCur->pStem = pStem->pNext; + sqlite3_free(pStem); + } + sqlite3_free(pCur); + return SQLITE_OK; +} + +static int fuzzerNext(sqlite3_vtab_cursor *cur){ + return 0; +} + +static int fuzzerFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor; + return fuzzerNext(pVtabCursor); +} + +static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + fuzzer_cursor *pCur = (fuzzer_cursor*)cur; + return SQLITE_OK; +} + +static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + *pRowid = 0; + return SQLITE_OK; +} + +static int fuzzerEof(sqlite3_vtab_cursor *cur){ + fuzzer_cursor *pCur = (fuzzer_cursor*)cur; + return 1; +} + +static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + + return SQLITE_OK; +} + +/* +** Disallow all attempts to DELETE or UPDATE. Only INSERTs are allowed. +** +** On an insert, the cFrom, cTo, and cost columns are used to construct +** a new rule. All other columns are ignored. The rule is ignored +** if cFrom and cTo are identical. A NULL value for cFrom or cTo is +** interpreted as an empty string. The cost must be positive. +*/ +static int fuzzerUpdate( + sqlite3_vtab *pVTab, + int argc, + sqlite3_value **argv, + sqlite_int64 *pRowid +){ + fuzzer_vtab *p = (fuzzer_vtab*)pVTab; + fuzzer_rule *pRule; + const char *zFrom; + int nFrom; + const char *zTo; + int nTo; + float rCost; + if( argc!=8 ){ + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = sqlite3_mprintf("cannot delete from a %s virtual table", + p->zClassName); + return SQLITE_CONSTRAINT; + } + if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){ + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = sqlite3_mprintf("cannot update a %s virtual table", + p->zClassName); + return SQLITE_CONSTRAINT; + } + zFrom = (char*)sqlite3_value_text(argv[4]); + if( zFrom==0 ) zFrom = ""; + zTo = (char*)sqlite3_value_text(argv[5]); + if( zTo==0 ) zTo = ""; + if( strcmp(zFrom,zTo)==0 ){ + /* Silently ignore null transformations */ + return SQLITE_OK; + } + rCost = (float)sqlite3_value_double(argv[6]); + if( rCost<=0 ){ + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = sqlite3_mprintf("cost must be positive"); + return SQLITE_CONSTRAINT; + } + nFrom = strlen(zFrom)+1; + nTo = strlen(zTo)+1; + if( nTo<4 ) nTo = 4; + pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo - 4 ); + if( pRule==0 ){ + return SQLITE_NOMEM; + } + pRule->zFrom = &pRule->zTo[nTo]; + memcpy(pRule->zFrom, zFrom, nFrom); + memcpy(pRule->zTo, zTo, nTo); + pRule->rCost = rCost; + pRule->pNext = p->pNewRule; + p->pNewRule = pRule; + return SQLITE_OK; +} + +/* +** A virtual table module that provides read-only access to a +** Tcl global variable namespace. +*/ +static sqlite3_module fuzzerModule = { + 0, /* iVersion */ + fuzzerConnect, + fuzzerConnect, + fuzzerBestIndex, + fuzzerDisconnect, + fuzzerDisconnect, + fuzzerOpen, /* xOpen - open a cursor */ + fuzzerClose, /* xClose - close a cursor */ + fuzzerFilter, /* xFilter - configure scan constraints */ + fuzzerNext, /* xNext - advance a cursor */ + fuzzerEof, /* xEof - check for end of scan */ + fuzzerColumn, /* xColumn - read data */ + fuzzerRowid, /* xRowid - read data */ + fuzzerUpdate, /* xUpdate - INSERT */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ +}; + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + +/* +** Register the fuzzer virtual table +*/ +int fuzzer_register(sqlite3 *db){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0); +#endif + return rc; +} + +#ifdef SQLITE_TEST +#include +/* +** Decode a pointer to an sqlite3 object. +*/ +extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); + +/* +** Register the echo virtual table module. +*/ +static int register_fuzzer_module( + ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int objc, /* Number of arguments */ + Tcl_Obj *CONST objv[] /* Command arguments */ +){ + sqlite3 *db; + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + fuzzer_register(db); + return TCL_OK; +} + + +/* +** Register commands with the TCL interpreter. +*/ +int Sqlitetestfuzzer_Init(Tcl_Interp *interp){ + static struct { + char *zName; + Tcl_ObjCmdProc *xProc; + void *clientData; + } aObjCmd[] = { + { "register_fuzzer_module", register_fuzzer_module, 0 }, + }; + int i; + for(i=0; i