aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-05-10 18:24:15 +0000
committerdrh <>2024-05-10 18:24:15 +0000
commit5d783d5c8490d1f115732e803152cf00b4ee4e15 (patch)
tree1955c55aefcb7f714c22620d5ced2705bcba5e93 /src
parent8292aa7a18da4d4f5b927bf396479f460ff6d041 (diff)
parente09e451a48f0e1ef74e15b3469f2dd78dee349a8 (diff)
downloadsqlite-5d783d5c8490d1f115732e803152cf00b4ee4e15.tar.gz
sqlite-5d783d5c8490d1f115732e803152cf00b4ee4e15.zip
Fix aggregate function processing to correctly deal with OOMs inside of
sqlite3ParserAddCleanup(). (dbsqlfuzz b2d11ca70e55ee8bde48ae0b53fa3e9355812f95). Also add improved testing support by causing sqlite3FaultSim(300) to simulate an OOM inside of sqlite3ParserAddCleanup() and by adding improved fault-sim support to the CLI. FossilOrigin-Name: c6fd70b3c23fa00eaac9286d4a67e5c8ac76f926c11c220250c34032647bedc1
Diffstat (limited to 'src')
-rw-r--r--src/expr.c14
-rw-r--r--src/prepare.c8
-rw-r--r--src/shell.c.in29
-rw-r--r--src/sqliteInt.h2
4 files changed, 38 insertions, 15 deletions
diff --git a/src/expr.c b/src/expr.c
index a5272df7c..27f89d659 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1443,11 +1443,11 @@ void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
**
** The pExpr might be deleted immediately on an OOM error.
**
-** The deferred delete is (currently) implemented by adding the
-** pExpr to the pParse->pConstExpr list with a register number of 0.
+** Return 0 if the delete was successfully deferred. Return non-zero
+** if the delete happened immediately because of an OOM.
*/
-void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
- sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr);
+int sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
+ return 0==sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr);
}
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
@@ -6681,9 +6681,8 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
&& pAggInfo->aCol[iAgg].pCExpr==pExpr
){
pExpr = sqlite3ExprDup(db, pExpr, 0);
- if( pExpr ){
+ if( pExpr && !sqlite3ExprDeferredDelete(pParse, pExpr) ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
- sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}else{
@@ -6692,9 +6691,8 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
&& pAggInfo->aFunc[iAgg].pFExpr==pExpr
){
pExpr = sqlite3ExprDup(db, pExpr, 0);
- if( pExpr ){
+ if( pExpr && !sqlite3ExprDeferredDelete(pParse, pExpr) ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
- sqlite3ExprDeferredDelete(pParse, pExpr);
}
}
}
diff --git a/src/prepare.c b/src/prepare.c
index 87569ee91..df9c98f74 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -633,7 +633,13 @@ void *sqlite3ParserAddCleanup(
void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */
void *pPtr /* Pointer to object to be cleaned up */
){
- ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
+ ParseCleanup *pCleanup;
+ if( sqlite3FaultSim(300) ){
+ pCleanup = 0;
+ sqlite3OomFault(pParse->db);
+ }else{
+ pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
+ }
if( pCleanup ){
pCleanup->pNext = pParse->pCleanup;
pParse->pCleanup = pCleanup;
diff --git a/src/shell.c.in b/src/shell.c.in
index 2f91ac8ba..298485344 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -7940,7 +7940,10 @@ static struct {
int iCnt; /* Trigger the fault only if iCnt is already zero */
int iInterval; /* Reset iCnt to this value after each fault */
int eVerbose; /* When to print output */
-} faultsim_state = {-1, 0, 0, 0, 0};
+ int nHit; /* Number of hits seen so far */
+ int nRepeat; /* Turn off after this many hits. 0 for never */
+ int nSkip; /* Skip this many before first fault */
+} faultsim_state = {-1, 0, 0, 0, 0, 0, 0};
/*
** This is the fault-sim callback
@@ -7949,8 +7952,8 @@ static int faultsim_callback(int iArg){
if( faultsim_state.iId>0 && faultsim_state.iId!=iArg ){
return SQLITE_OK;
}
- if( faultsim_state.iCnt>0 ){
- faultsim_state.iCnt--;
+ if( faultsim_state.iCnt ){
+ if( faultsim_state.iCnt>0 ) faultsim_state.iCnt--;
if( faultsim_state.eVerbose>=2 ){
oputf("FAULT-SIM id=%d no-fault (cnt=%d)\n", iArg, faultsim_state.iCnt);
}
@@ -7960,6 +7963,10 @@ static int faultsim_callback(int iArg){
oputf("FAULT-SIM id=%d returns %d\n", iArg, faultsim_state.iErr);
}
faultsim_state.iCnt = faultsim_state.iInterval;
+ faultsim_state.nHit++;
+ if( faultsim_state.nRepeat>0 && faultsim_state.nRepeat<=faultsim_state.nHit ){
+ faultsim_state.iCnt = -1;
+ }
return faultsim_state.iErr;
}
@@ -11121,17 +11128,23 @@ static int do_meta_command(char *zLine, ShellState *p){
if( cli_strcmp(z,"off")==0 ){
sqlite3_test_control(testctrl, 0);
}else if( cli_strcmp(z,"on")==0 ){
- faultsim_state.iCnt = faultsim_state.iInterval;
+ faultsim_state.iCnt = faultsim_state.nSkip;
if( faultsim_state.iErr==0 ) faultsim_state.iErr = 1;
+ faultsim_state.nHit = 0;
sqlite3_test_control(testctrl, faultsim_callback);
}else if( cli_strcmp(z,"reset")==0 ){
- faultsim_state.iCnt = faultsim_state.iInterval;
+ faultsim_state.iCnt = faultsim_state.nSkip;
+ faultsim_state.nHit = 0;
+ sqlite3_test_control(testctrl, faultsim_callback);
}else if( cli_strcmp(z,"status")==0 ){
oputf("faultsim.iId: %d\n", faultsim_state.iId);
oputf("faultsim.iErr: %d\n", faultsim_state.iErr);
oputf("faultsim.iCnt: %d\n", faultsim_state.iCnt);
+ oputf("faultsim.nHit: %d\n", faultsim_state.nHit);
oputf("faultsim.iInterval: %d\n", faultsim_state.iInterval);
oputf("faultsim.eVerbose: %d\n", faultsim_state.eVerbose);
+ oputf("faultsim.nRepeat: %d\n", faultsim_state.nRepeat);
+ oputf("faultsim.nSkip: %d\n", faultsim_state.nSkip);
}else if( cli_strcmp(z,"-v")==0 ){
if( faultsim_state.eVerbose<2 ) faultsim_state.eVerbose++;
}else if( cli_strcmp(z,"-q")==0 ){
@@ -11142,6 +11155,10 @@ static int do_meta_command(char *zLine, ShellState *p){
faultsim_state.iErr = atoi(azArg[++kk]);
}else if( cli_strcmp(z,"-interval")==0 && kk+1<nArg ){
faultsim_state.iInterval = atoi(azArg[++kk]);
+ }else if( cli_strcmp(z,"-repeat")==0 && kk+1<nArg ){
+ faultsim_state.nRepeat = atoi(azArg[++kk]);
+ }else if( cli_strcmp(z,"-skip")==0 && kk+1<nArg ){
+ faultsim_state.nSkip = atoi(azArg[++kk]);
}else if( cli_strcmp(z,"-?")==0 || sqlite3_strglob("*help*",z)==0){
bShowHelp = 1;
}else{
@@ -11165,6 +11182,8 @@ static int do_meta_command(char *zLine, ShellState *p){
" --errcode N When triggered, return N as error code\n"
" --id ID Trigger only for the ID specified\n"
" --interval N Trigger only after every N-th call\n"
+ " --repeat N Turn off after N hits. 0 means never\n"
+ " --skip N Skip the first N encounters\n"
);
}
break;
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 0da289d52..aa8bfc4b7 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -4856,7 +4856,7 @@ void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
void sqlite3ExprDelete(sqlite3*, Expr*);
void sqlite3ExprDeleteGeneric(sqlite3*,void*);
-void sqlite3ExprDeferredDelete(Parse*, Expr*);
+int sqlite3ExprDeferredDelete(Parse*, Expr*);
void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);