mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-08 03:22:21 +03:00
Further improvements to the fuzzer. It still is not quite working. Pausing
to work on other things.... FossilOrigin-Name: 5f2f2fce40f43debeb0492c9b460b85c7dad2bde
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
@@ -49,7 +50,15 @@ struct fuzzer_rule {
|
||||
};
|
||||
|
||||
/*
|
||||
** A stem object is used to generate variants.
|
||||
** A stem object is used to generate variants. It is also used to record
|
||||
** previously generated outputs.
|
||||
**
|
||||
** Every stem is added to a hash table as it is output. Generation of
|
||||
** duplicate stems is suppressed.
|
||||
**
|
||||
** Active stems (those that might generate new outputs) are kepts on a linked
|
||||
** list sorted by increasing cost. The cost is the sum of rBaseCost and
|
||||
** pRule->rCost.
|
||||
*/
|
||||
struct fuzzer_stem {
|
||||
char *zBasis; /* Word being fuzzed */
|
||||
@@ -83,6 +92,7 @@ struct fuzzer_cursor {
|
||||
fuzzer_stem *pDone; /* Stems already processed to completion */
|
||||
char *zBuf; /* Temporary use buffer */
|
||||
int nBuf; /* Bytes allocated for zBuf */
|
||||
fuzzer_rule nullRule; /* Null rule used first */
|
||||
fuzzer_stem *apHash[FUZZER_HASH]; /* Hash of previously generated terms */
|
||||
};
|
||||
|
||||
@@ -171,7 +181,6 @@ static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->pVtab = p;
|
||||
*ppCursor = &pCur->base;
|
||||
p->nCursor++;
|
||||
if( p->nCursor==0 && p->pNewRule ){
|
||||
unsigned int i;
|
||||
fuzzer_rule *pX;
|
||||
@@ -191,6 +200,7 @@ static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
}
|
||||
p->pRule = fuzzerMergeRules(p->pRule, pX);
|
||||
}
|
||||
p->nCursor++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -221,35 +231,34 @@ static int fuzzerClose(sqlite3_vtab_cursor *cur){
|
||||
fuzzerClearCursor(pCur, 0);
|
||||
sqlite3_free(pCur->zBuf);
|
||||
pCur->pVtab->nCursor--;
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the current output term for a fuzzer_stem.
|
||||
*/
|
||||
static int fuzzerComputeWord(
|
||||
fuzzer_cursor *pCur,
|
||||
fuzzer_stem *pStem
|
||||
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;
|
||||
char *z;
|
||||
|
||||
n = pStem->nBasis;
|
||||
if( pStem->n>=0 ) n += pRule->nTo - pRule->nFrom;
|
||||
if( pCur->nBuf<n+1 ){
|
||||
pCur->zBuf = sqlite3_realloc(pCur->zBuf, n+100);
|
||||
if( pCur->zBuf==0 ) return SQLITE_NOMEM;
|
||||
pCur->nBuf = n+100;
|
||||
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;
|
||||
if( n<0 ){
|
||||
memcpy(pCur->zBuf, pStem->zBasis, pStem->nBasis+1);
|
||||
}else{
|
||||
memcpy(pCur->zBuf, pStem->zBasis, n);
|
||||
memcpy(&pCur->zBuf[n], pRule->zTo, pRule->nTo);
|
||||
memcpy(&pCur->zBuf[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom],
|
||||
pStem->nBasis-n-pRule->nFrom+1);
|
||||
}
|
||||
z = *pzBuf;
|
||||
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);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -260,7 +269,7 @@ static int fuzzerComputeWord(
|
||||
static unsigned int fuzzerHash(const char *z){
|
||||
unsigned int h = 0;
|
||||
while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); }
|
||||
return h%10007;
|
||||
return h % FUZZER_HASH;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -270,9 +279,30 @@ static fuzzer_cost fuzzerCost(fuzzer_stem *pStem){
|
||||
return pStem->rBaseCost + pStem->pRule->rCost;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return 1 if the string to which the cursor is point has already
|
||||
** been emitted. Return 0 if not. Return -1 on a memory allocation
|
||||
** failures.
|
||||
*/
|
||||
static int fuzzerSeen(fuzzer_cursor *pCur, fuzzer_stem *pStem){
|
||||
unsigned int h;
|
||||
fuzzer_stem *pLookup;
|
||||
|
||||
if( fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
|
||||
return -1;
|
||||
}
|
||||
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.
|
||||
** 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;
|
||||
@@ -283,21 +313,14 @@ static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
|
||||
|| memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0
|
||||
){
|
||||
/* Found a rewrite case. Make sure it is not a duplicate */
|
||||
unsigned int h;
|
||||
fuzzer_stem *pLookup;
|
||||
|
||||
fuzzerComputeWord(pCur, pStem);
|
||||
h = fuzzerHash(pCur->zBuf);
|
||||
pLookup = pCur->apHash[h];
|
||||
while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){
|
||||
pLookup = pLookup->pHash;
|
||||
}
|
||||
if( pLookup==0 ) return 1; /* A new output is found. */
|
||||
int rc = fuzzerSeen(pCur, pStem);
|
||||
if( rc<0 ) return -1;
|
||||
if( rc==0 ) return 1;
|
||||
}
|
||||
}
|
||||
pStem->n = -1;
|
||||
pStem->pRule = pRule->pNext;
|
||||
if( fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
|
||||
if( pStem->pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -310,6 +333,10 @@ static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
|
||||
static fuzzer_stem *fuzzerInsert(fuzzer_stem *pList, fuzzer_stem *pNew){
|
||||
fuzzer_cost c1;
|
||||
|
||||
if( pList==0 ){
|
||||
pNew->pNext = 0;
|
||||
return pNew;
|
||||
}
|
||||
c1 = fuzzerCost(pNew);
|
||||
if( c1 <= fuzzerCost(pList) ){
|
||||
pNew->pNext = pList;
|
||||
@@ -358,20 +385,30 @@ static fuzzer_stem *fuzzerNewStem(
|
||||
** Advance a cursor to its next row of output
|
||||
*/
|
||||
static int fuzzerNext(sqlite3_vtab_cursor *cur){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor*)pCur;
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
|
||||
int rc;
|
||||
fuzzer_stem *pStem, *pNew;
|
||||
|
||||
/* Use the element the cursor is currently point to to create
|
||||
** a new stem and insert the new stem into the priority queue.
|
||||
*/
|
||||
fuzzerComputeWord(pCur, pCur->pStem);
|
||||
pNew = fuzzerNewStem(pCur, pCur->zBuf, fuzzerCost(pCur->pStem));
|
||||
if( pNew ){
|
||||
if( fuzzerAdvance(pCur, pNew)==0 ){
|
||||
pNew->pNext = pCur->pDone;
|
||||
pCur->pDone = pNew;
|
||||
pStem = pCur->pStem;
|
||||
if( fuzzerCost(pStem)>0 ){
|
||||
rc = fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf);
|
||||
if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
|
||||
pNew = fuzzerNewStem(pCur, pCur->zBuf, fuzzerCost(pStem));
|
||||
if( pNew ){
|
||||
if( fuzzerAdvance(pCur, pNew)==0 ){
|
||||
pNew->pNext = pCur->pDone;
|
||||
pCur->pDone = pNew;
|
||||
}else{
|
||||
pCur->pStem = fuzzerInsert(pStem, pNew);
|
||||
if( pCur->pStem==pNew ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pCur->pStem = fuzzerInsert(pCur->pStem, pNew);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +418,12 @@ static int fuzzerNext(sqlite3_vtab_cursor *cur){
|
||||
while( (pStem = pCur->pStem)!=0 ){
|
||||
if( fuzzerAdvance(pCur, pStem) ){
|
||||
pCur->pStem = fuzzerInsert(pStem->pNext, pStem);
|
||||
return SQLITE_OK; /* New word found */
|
||||
if( pCur->pStem!=pStem && (rc = fuzzerSeen(pCur, pStem))!=0 ){
|
||||
if( rc<0 ) return SQLITE_NOMEM;
|
||||
continue;
|
||||
}else{
|
||||
return SQLITE_OK; /* New word found */
|
||||
}
|
||||
}
|
||||
pCur->pStem = pStem->pNext;
|
||||
pStem->pNext = pCur->pDone;
|
||||
@@ -406,9 +448,10 @@ static int fuzzerFilter(
|
||||
){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor;
|
||||
const char *zWord = 0;
|
||||
pCur->rLimit = 2147483647;
|
||||
fuzzer_stem *pStem;
|
||||
|
||||
fuzzerClearCursor(pCur, 1);
|
||||
pCur->rLimit = 2147483647;
|
||||
if( idxNum==1 ){
|
||||
zWord = (const char*)sqlite3_value_text(argv[0]);
|
||||
}else if( idxNum==2 ){
|
||||
@@ -418,8 +461,15 @@ static int fuzzerFilter(
|
||||
pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[1]);
|
||||
}
|
||||
if( zWord==0 ) zWord = "";
|
||||
pCur->pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0);
|
||||
if( pCur->pStem==0 ) return SQLITE_NOMEM;
|
||||
pCur->pStem = pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0);
|
||||
if( pStem==0 ) return SQLITE_NOMEM;
|
||||
pCur->nullRule.pNext = pCur->pVtab->pRule;
|
||||
pCur->nullRule.rCost = 0;
|
||||
pCur->nullRule.nFrom = 0;
|
||||
pCur->nullRule.nTo = 0;
|
||||
pCur->nullRule.zFrom = "";
|
||||
pStem->pRule = &pCur->nullRule;
|
||||
pStem->n = pStem->nBasis;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -431,7 +481,7 @@ static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
|
||||
if( i==0 ){
|
||||
/* the "word" column */
|
||||
if( fuzzerComputeWord(pCur, pCur->pStem)==SQLITE_NOMEM ){
|
||||
if( fuzzerRender(pCur->pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT);
|
||||
@@ -567,17 +617,16 @@ static int fuzzerUpdate(
|
||||
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 );
|
||||
nFrom = strlen(zFrom);
|
||||
nTo = strlen(zTo);
|
||||
pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
|
||||
if( pRule==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pRule->zFrom = &pRule->zTo[nTo];
|
||||
pRule->zFrom = &pRule->zTo[nTo+1];
|
||||
pRule->nFrom = nFrom;
|
||||
memcpy(pRule->zFrom, zFrom, nFrom);
|
||||
memcpy(pRule->zTo, zTo, nTo);
|
||||
memcpy(pRule->zFrom, zFrom, nFrom+1);
|
||||
memcpy(pRule->zTo, zTo, nTo+1);
|
||||
pRule->nTo = nTo;
|
||||
pRule->rCost = rCost;
|
||||
pRule->pNext = p->pNewRule;
|
||||
|
||||
Reference in New Issue
Block a user