aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2016-12-23 13:52:45 +0000
committerdrh <drh@noemail.net>2016-12-23 13:52:45 +0000
commitce1bbe51b5c57b6487e92fe83c5c168a84c9e051 (patch)
tree334b07f003c4e05a9796f5eb50211760826f6617 /src
parentf326d66d618c50bfcb348e3023793524da25c28b (diff)
downloadsqlite-ce1bbe51b5c57b6487e92fe83c5c168a84c9e051.tar.gz
sqlite-ce1bbe51b5c57b6487e92fe83c5c168a84c9e051.zip
Add check to prevent a VList from growing after pointers to labels have been
taken. FossilOrigin-Name: aa23d7eaf69f5ecbf9500b2353846094cae41e6c
Diffstat (limited to 'src')
-rw-r--r--src/expr.c1
-rw-r--r--src/util.c32
2 files changed, 24 insertions, 9 deletions
diff --git a/src/expr.c b/src/expr.c
index 3f8406bc5..ecc6c7928 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3422,6 +3422,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( pExpr->u.zToken[1]!=0 ){
const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 );
+ pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
}
return target;
diff --git a/src/util.c b/src/util.c
index 5ece9226f..b9684c6c0 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1457,7 +1457,7 @@ u64 sqlite3LogEstToInt(LogEst x){
/*
** Add a new name/number pair to a VList. This might require that the
** VList object be reallocated, so return the new VList. If an OOM
-** error occurs, the original VList freed, NULL is returned, and the
+** error occurs, the original VList returned and the
** db->mallocFailed flag is set.
**
** A VList is really just an array of integers. To destroy a VList,
@@ -1468,11 +1468,27 @@ u64 sqlite3LogEstToInt(LogEst x){
** Each name/number pair is encoded by subsequent groups of 3 or more
** integers.
**
-** Each name/number pair starts with two integers which are the number
+** Each name/number pair starts with two integers which are the numeric
** value for the pair and the size of the name/number pair, respectively.
** The text name overlays one or more following integers. The text name
** is always zero-terminated.
-**
+**
+** Conceptually:
+**
+** struct VList {
+** int nAlloc; // Number of allocated slots
+** int nUsed; // Number of used slots
+** struct VListEntry {
+** int iValue; // Value for this entry
+** int nSlot; // Slots used by this entry
+** // ... variable name goes here
+** } a[0];
+** }
+**
+** During code generation, pointers to the variable names within the
+** VList are taken. When that happens, nAlloc is set to zero as an
+** indication that the VList may never again be enlarged, since the
+** accompanying realloc() would invalidate the pointers.
*/
VList *sqlite3VListAdd(
sqlite3 *db, /* The database connection used for malloc() */
@@ -1482,18 +1498,16 @@ VList *sqlite3VListAdd(
int iVal /* Value to associate with zName */
){
int nInt; /* number of sizeof(int) objects needed for zName */
- char *z;
- int i;
+ char *z; /* Pointer to where zName will be stored */
+ int i; /* Index in pIn[] where zName is stored */
nInt = nName/4 + 3;
+ assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */
if( pIn==0 || pIn[1]+nInt > pIn[0] ){
/* Enlarge the allocation */
int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt;
VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int));
- if( pOut==0 ){
- sqlite3DbFree(db, pIn);
- return 0;
- }
+ if( pOut==0 ) return pIn;
if( pIn==0 ) pOut[1] = 2;
pIn = pOut;
pIn[0] = nAlloc;