/ Check-in [0064bab7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Change the VDBE so that all registers are initialized to "Invalid" instead of NULL and report errors on any attempted read of an Invalid register. This will help prevent future bugs similar to [7bbfb7d442].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0064bab77149768640d7758a3e271d5a1d63b256
User & Date: drh 2011-12-09 18:06:44
References
2012-12-06
20:19
Cherrypick [557c69055a3] and [0064bab7714] (OP_Once-related fixes for triggers). check-in: 0d7b5d45 user: dan tags: branch-3.7.9
Context
2011-12-10
13:49
Always use _msize() to get memory allocation sizes on windows, without having to do anything special in the makefile. check-in: 256e27bd user: drh tags: trunk
2011-12-09
18:06
Change the VDBE so that all registers are initialized to "Invalid" instead of NULL and report errors on any attempted read of an Invalid register. This will help prevent future bugs similar to [7bbfb7d442]. check-in: 0064bab7 user: drh tags: trunk
17:51
Remove an unnecessary condition. Closed-Leaf check-in: d9ba023c user: drh tags: uninit-vdbe-mem
13:24
Modify the OP_Once opcode so that it works correctly in trigger sub-programs. This is a candidate fix for [7bbfb7d442]. check-in: 557c6905 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  1440   1440   */
  1441   1441   #ifndef SQLITE_OMIT_SUBQUERY
  1442   1442   int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
  1443   1443     Select *p;                            /* SELECT to the right of IN operator */
  1444   1444     int eType = 0;                        /* Type of RHS table. IN_INDEX_* */
  1445   1445     int iTab = pParse->nTab++;            /* Cursor of the RHS table */
  1446   1446     int mustBeUnique = (prNotFound==0);   /* True if RHS must be unique */
         1447  +  Vdbe *v = sqlite3GetVdbe(pParse);     /* Virtual machine being coded */
  1447   1448   
  1448   1449     assert( pX->op==TK_IN );
  1449   1450   
  1450   1451     /* Check to see if an existing table or index can be used to
  1451   1452     ** satisfy the query.  This is preferable to generating a new 
  1452   1453     ** ephemeral table.
  1453   1454     */
  1454   1455     p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
  1455   1456     if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
  1456   1457       sqlite3 *db = pParse->db;              /* Database connection */
  1457         -    Vdbe *v = sqlite3GetVdbe(pParse);      /* Virtual machine being coded */
  1458   1458       Table *pTab;                           /* Table <table>. */
  1459   1459       Expr *pExpr;                           /* Expression <column> */
  1460   1460       int iCol;                              /* Index of column <column> */
  1461   1461       int iDb;                               /* Database idx for pTab */
  1462   1462   
  1463   1463       assert( p );                        /* Because of isCandidateForInOpt(p) */
  1464   1464       assert( p->pEList!=0 );             /* Because of isCandidateForInOpt(p) */
................................................................................
  1517   1517                                  pKey,P4_KEYINFO_HANDOFF);
  1518   1518             VdbeComment((v, "%s", pIdx->zName));
  1519   1519             eType = IN_INDEX_INDEX;
  1520   1520   
  1521   1521             sqlite3VdbeJumpHere(v, iAddr);
  1522   1522             if( prNotFound && !pTab->aCol[iCol].notNull ){
  1523   1523               *prNotFound = ++pParse->nMem;
         1524  +            sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
  1524   1525             }
  1525   1526           }
  1526   1527         }
  1527   1528       }
  1528   1529     }
  1529   1530   
  1530   1531     if( eType==0 ){
................................................................................
  1532   1533       ** We will have to generate an ephemeral table to do the job.
  1533   1534       */
  1534   1535       double savedNQueryLoop = pParse->nQueryLoop;
  1535   1536       int rMayHaveNull = 0;
  1536   1537       eType = IN_INDEX_EPH;
  1537   1538       if( prNotFound ){
  1538   1539         *prNotFound = rMayHaveNull = ++pParse->nMem;
         1540  +      sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
  1539   1541       }else{
  1540   1542         testcase( pParse->nQueryLoop>(double)1 );
  1541   1543         pParse->nQueryLoop = (double)1;
  1542   1544         if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
  1543   1545           eType = IN_INDEX_ROWID;
  1544   1546         }
  1545   1547       }

Changes to src/insert.c.

   235    235   
   236    236     assert( v );   /* We failed long ago if this is not so */
   237    237     for(p = pParse->pAinc; p; p = p->pNext){
   238    238       pDb = &db->aDb[p->iDb];
   239    239       memId = p->regCtr;
   240    240       assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
   241    241       sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
          242  +    sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
   242    243       addr = sqlite3VdbeCurrentAddr(v);
   243    244       sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
   244    245       sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
   245    246       sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
   246    247       sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId);
   247    248       sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
   248    249       sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);

Changes to src/select.c.

  4150   4150         pParse->nMem += pGroupBy->nExpr;
  4151   4151         iBMem = pParse->nMem + 1;
  4152   4152         pParse->nMem += pGroupBy->nExpr;
  4153   4153         sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
  4154   4154         VdbeComment((v, "clear abort flag"));
  4155   4155         sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
  4156   4156         VdbeComment((v, "indicate accumulator empty"));
         4157  +      sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
  4157   4158   
  4158   4159         /* Begin a loop that will extract all source rows in GROUP BY order.
  4159   4160         ** This might involve two separate loops with an OP_Sort in between, or
  4160   4161         ** it might be a single loop that uses an index to extract information
  4161   4162         ** in the right order to begin with.
  4162   4163         */
  4163   4164         sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);

Changes to src/update.c.

   122    122   #endif
   123    123     int newmask;           /* Mask of NEW.* columns accessed by BEFORE triggers */
   124    124   
   125    125     /* Register Allocations */
   126    126     int regRowCount = 0;   /* A count of rows changed */
   127    127     int regOldRowid;       /* The old rowid */
   128    128     int regNewRowid;       /* The new rowid */
   129         -  int regNew;
   130         -  int regOld = 0;
          129  +  int regNew;            /* Content of the NEW.* table in triggers */
          130  +  int regOld = 0;        /* Content of OLD.* table in triggers */
   131    131     int regRowSet = 0;     /* Rowset of rows to be updated */
   132    132   
   133    133     memset(&sContext, 0, sizeof(sContext));
   134    134     db = pParse->db;
   135    135     if( pParse->nErr || db->mallocFailed ){
   136    136       goto update_cleanup;
   137    137     }
................................................................................
   272    272       pWhere = 0;
   273    273       pTabList = 0;
   274    274       goto update_cleanup;
   275    275     }
   276    276   #endif
   277    277   
   278    278     /* Allocate required registers. */
          279  +  regRowSet = ++pParse->nMem;
   279    280     regOldRowid = regNewRowid = ++pParse->nMem;
   280    281     if( pTrigger || hasFK ){
   281    282       regOld = pParse->nMem + 1;
   282    283       pParse->nMem += pTab->nCol;
   283    284     }
   284    285     if( chngRowid || pTrigger || hasFK ){
   285    286       regNewRowid = ++pParse->nMem;
................................................................................
   306    307     */
   307    308     if( sqlite3ResolveExprNames(&sNC, pWhere) ){
   308    309       goto update_cleanup;
   309    310     }
   310    311   
   311    312     /* Begin the database scan
   312    313     */
   313         -  sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
          314  +  sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
   314    315     pWInfo = sqlite3WhereBegin(
   315    316         pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
   316    317     );
   317    318     if( pWInfo==0 ) goto update_cleanup;
   318    319     okOnePass = pWInfo->okOnePass;
   319    320   
   320    321     /* Remember the rowid of every item to be updated.
   321    322     */
   322    323     sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
   323    324     if( !okOnePass ){
   324         -    regRowSet = ++pParse->nMem;
   325    325       sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
   326    326     }
   327    327   
   328    328     /* End the database scan loop.
   329    329     */
   330    330     sqlite3WhereEnd(pWInfo);
   331    331   
................................................................................
   421    421     ** the database after the BEFORE triggers are fired anyway (as the trigger 
   422    422     ** may have modified them). So not loading those that are not going to
   423    423     ** be used eliminates some redundant opcodes.
   424    424     */
   425    425     newmask = sqlite3TriggerColmask(
   426    426         pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
   427    427     );
          428  +  sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
   428    429     for(i=0; i<pTab->nCol; i++){
   429    430       if( i==pTab->iPKey ){
   430         -      sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
          431  +      /*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
   431    432       }else{
   432    433         j = aXRef[i];
   433    434         if( j>=0 ){
   434    435           sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
   435    436         }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
   436    437           /* This branch loads the value of a column that will not be changed 
   437    438           ** into a register. This is done if there are no BEFORE triggers, or

Changes to src/vdbe.c.

   760    760   }
   761    761   
   762    762   /* Opcode:  Gosub P1 P2 * * *
   763    763   **
   764    764   ** Write the current address onto register P1
   765    765   ** and then jump to address P2.
   766    766   */
   767         -case OP_Gosub: {            /* jump, in1 */
          767  +case OP_Gosub: {            /* jump */
          768  +  assert( pOp->p1>0 && pOp->p1<=p->nMem );
   768    769     pIn1 = &aMem[pOp->p1];
   769    770     assert( (pIn1->flags & MEM_Dyn)==0 );
   770    771     memAboutToChange(p, pIn1);
   771    772     pIn1->flags = MEM_Int;
   772    773     pIn1->u.i = pc;
   773    774     REGISTER_TRACE(pOp->p1, pIn1);
   774    775     pc = pOp->p2 - 1;
................................................................................
   957    958     pOut->z = pOp->p4.z;
   958    959     pOut->n = pOp->p1;
   959    960     pOut->enc = encoding;
   960    961     UPDATE_MAX_BLOBSIZE(pOut);
   961    962     break;
   962    963   }
   963    964   
   964         -/* Opcode: Null * P2 * * *
          965  +/* Opcode: Null * P2 P3 * *
   965    966   **
   966         -** Write a NULL into register P2.
          967  +** Write a NULL into registers P2.  If P3 greater than P2, then also write
          968  +** NULL into register P3 and ever register in between P2 and P3.  If P3
          969  +** is less than P2 (typically P3 is zero) then only register P2 is
          970  +** set to NULL
   967    971   */
   968    972   case OP_Null: {           /* out2-prerelease */
          973  +  int cnt;
          974  +  cnt = pOp->p3-pOp->p2;
          975  +  assert( pOp->p3<=p->nMem );
   969    976     pOut->flags = MEM_Null;
          977  +  while( cnt>0 ){
          978  +    pOut++;
          979  +    memAboutToChange(p, pOut);
          980  +    MemReleaseExt(pOut);
          981  +    pOut->flags = MEM_Null;
          982  +    cnt--;
          983  +  }
   970    984     break;
   971    985   }
   972    986   
   973    987   
   974    988   /* Opcode: Blob P1 P2 * P4
   975    989   **
   976    990   ** P4 points to a blob of data P1 bytes long.  Store this
................................................................................
  2021   2035     break;
  2022   2036   }
  2023   2037   
  2024   2038   /* Opcode: Once P1 P2 * * *
  2025   2039   **
  2026   2040   ** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
  2027   2041   ** set the flag and fall through to the next instruction.
         2042  +**
         2043  +** See also: JumpOnce
  2028   2044   */
  2029   2045   case OP_Once: {             /* jump */
  2030   2046     assert( pOp->p1<p->nOnceFlag );
  2031   2047     if( p->aOnceFlag[pOp->p1] ){
  2032   2048       pc = pOp->p2-1;
  2033   2049     }else{
  2034   2050       p->aOnceFlag[pOp->p1] = 1;
................................................................................
  2036   2052     break;
  2037   2053   }
  2038   2054   
  2039   2055   /* Opcode: If P1 P2 P3 * *
  2040   2056   **
  2041   2057   ** Jump to P2 if the value in register P1 is true.  The value
  2042   2058   ** is considered true if it is numeric and non-zero.  If the value
  2043         -** in P1 is NULL then take the jump if P3 is true.
         2059  +** in P1 is NULL then take the jump if P3 is non-zero.
  2044   2060   */
  2045   2061   /* Opcode: IfNot P1 P2 P3 * *
  2046   2062   **
  2047   2063   ** Jump to P2 if the value in register P1 is False.  The value
  2048         -** is considered true if it has a numeric value of zero.  If the value
  2049         -** in P1 is NULL then take the jump if P3 is true.
         2064  +** is considered false if it has a numeric value of zero.  If the value
         2065  +** in P1 is NULL then take the jump if P3 is zero.
  2050   2066   */
  2051   2067   case OP_If:                 /* jump, in1 */
  2052   2068   case OP_IfNot: {            /* jump, in1 */
  2053   2069     int c;
  2054   2070     pIn1 = &aMem[pOp->p1];
  2055   2071     if( pIn1->flags & MEM_Null ){
  2056   2072       c = pOp->p3;
................................................................................
  5065   5081     Mem *pEnd;              /* Last memory cell in new array */
  5066   5082     VdbeFrame *pFrame;      /* New vdbe frame to execute in */
  5067   5083     SubProgram *pProgram;   /* Sub-program to execute */
  5068   5084     void *t;                /* Token identifying trigger */
  5069   5085   
  5070   5086     pProgram = pOp->p4.pProgram;
  5071   5087     pRt = &aMem[pOp->p3];
  5072         -  assert( memIsValid(pRt) );
  5073   5088     assert( pProgram->nOp>0 );
  5074   5089     
  5075   5090     /* If the p5 flag is clear, then recursive invocation of triggers is 
  5076   5091     ** disabled for backwards compatibility (p5 is set if this sub-program
  5077   5092     ** is really a trigger, not a foreign key action, and the flag set
  5078   5093     ** and cleared by the "PRAGMA recursive_triggers" command is clear).
  5079   5094     ** 
................................................................................
  5130   5145       pFrame->nOp = p->nOp;
  5131   5146       pFrame->token = pProgram->token;
  5132   5147       pFrame->aOnceFlag = p->aOnceFlag;
  5133   5148       pFrame->nOnceFlag = p->nOnceFlag;
  5134   5149   
  5135   5150       pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
  5136   5151       for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
  5137         -      pMem->flags = MEM_Null;
         5152  +      pMem->flags = MEM_Invalid;
  5138   5153         pMem->db = db;
  5139   5154       }
  5140   5155     }else{
  5141   5156       pFrame = pRt->u.pFrame;
  5142   5157       assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
  5143   5158       assert( pProgram->nCsr==pFrame->nChildCsr );
  5144   5159       assert( pc==pFrame->pc );

Changes to src/vdbeaux.c.

   909    909       }
   910    910       case P4_REAL: {
   911    911         sqlite3_snprintf(nTemp, zTemp, "%.16g", *pOp->p4.pReal);
   912    912         break;
   913    913       }
   914    914       case P4_MEM: {
   915    915         Mem *pMem = pOp->p4.pMem;
   916         -      assert( (pMem->flags & MEM_Null)==0 );
   917    916         if( pMem->flags & MEM_Str ){
   918    917           zP4 = pMem->z;
   919    918         }else if( pMem->flags & MEM_Int ){
   920    919           sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
   921    920         }else if( pMem->flags & MEM_Real ){
   922    921           sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
          922  +      }else if( pMem->flags & MEM_Null ){
          923  +        sqlite3_snprintf(nTemp, zTemp, "NULL");
   923    924         }else{
   924    925           assert( pMem->flags & MEM_Blob );
   925    926           zP4 = "(blob)";
   926    927         }
   927    928         break;
   928    929       }
   929    930   #ifndef SQLITE_OMIT_VIRTUALTABLE
................................................................................
  1090   1091         if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
  1091   1092           sqlite3VdbeMemRelease(p);
  1092   1093         }else if( p->zMalloc ){
  1093   1094           sqlite3DbFree(db, p->zMalloc);
  1094   1095           p->zMalloc = 0;
  1095   1096         }
  1096   1097   
  1097         -      p->flags = MEM_Null;
         1098  +      p->flags = MEM_Invalid;
  1098   1099       }
  1099   1100       db->mallocFailed = malloc_failed;
  1100   1101     }
  1101   1102   }
  1102   1103   
  1103   1104   /*
  1104   1105   ** Delete a VdbeFrame object and its contents. VdbeFrame objects are
................................................................................
  1528   1529       nByte = 0;
  1529   1530       p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
  1530   1531       p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
  1531   1532       p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
  1532   1533       p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
  1533   1534       p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
  1534   1535                             &zCsr, zEnd, &nByte);
  1535         -    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce*sizeof(u8), 
  1536         -                          &zCsr, zEnd, &nByte);
         1536  +    p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
  1537   1537       if( nByte ){
  1538   1538         p->pFree = sqlite3DbMallocZero(db, nByte);
  1539   1539       }
  1540   1540       zCsr = p->pFree;
  1541   1541       zEnd = &zCsr[nByte];
  1542   1542     }while( nByte && !db->mallocFailed );
  1543   1543   
................................................................................
  1555   1555       memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
  1556   1556       memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
  1557   1557     }
  1558   1558     if( p->aMem ){
  1559   1559       p->aMem--;                      /* aMem[] goes from 1..nMem */
  1560   1560       p->nMem = nMem;                 /*       not from 0..nMem-1 */
  1561   1561       for(n=1; n<=nMem; n++){
  1562         -      p->aMem[n].flags = MEM_Null;
         1562  +      p->aMem[n].flags = MEM_Invalid;
  1563   1563         p->aMem[n].db = db;
  1564   1564       }
  1565   1565     }
  1566   1566     p->explain = pParse->explain;
  1567   1567     sqlite3VdbeRewind(p);
  1568   1568   }
  1569   1569   
................................................................................
  1645   1645       releaseMemArray(&p->aMem[1], p->nMem);
  1646   1646     }
  1647   1647     while( p->pDelFrame ){
  1648   1648       VdbeFrame *pDel = p->pDelFrame;
  1649   1649       p->pDelFrame = pDel->pParent;
  1650   1650       sqlite3VdbeFrameDelete(pDel);
  1651   1651     }
  1652         -  memset(p->aOnceFlag, 0, p->nOnceFlag);
  1653   1652   }
  1654   1653   
  1655   1654   /*
  1656   1655   ** Clean up the VM after execution.
  1657   1656   **
  1658   1657   ** This routine will automatically close any cursors, lists, and/or
  1659   1658   ** sorters that were left open.  It also deletes the values of
................................................................................
  1662   1661   static void Cleanup(Vdbe *p){
  1663   1662     sqlite3 *db = p->db;
  1664   1663   
  1665   1664   #ifdef SQLITE_DEBUG
  1666   1665     /* Execute assert() statements to ensure that the Vdbe.apCsr[] and 
  1667   1666     ** Vdbe.aMem[] arrays have already been cleaned up.  */
  1668   1667     int i;
  1669         -  for(i=0; i<p->nCursor; i++) assert( p->apCsr==0 || p->apCsr[i]==0 );
  1670         -  for(i=1; i<=p->nMem; i++) assert( p->aMem==0 || p->aMem[i].flags==MEM_Null );
         1668  +  if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
         1669  +  if( p->aMem ){
         1670  +    for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
         1671  +  }
  1671   1672   #endif
  1672   1673   
  1673   1674     sqlite3DbFree(db, p->zErrMsg);
  1674   1675     p->zErrMsg = 0;
  1675   1676     p->pResultSet = 0;
  1676   1677   }
  1677   1678   
................................................................................
  2131   2132     ** state.  We need to rollback the statement transaction, if there is
  2132   2133     ** one, or the complete transaction if there is no statement transaction.
  2133   2134     */
  2134   2135   
  2135   2136     if( p->db->mallocFailed ){
  2136   2137       p->rc = SQLITE_NOMEM;
  2137   2138     }
         2139  +  if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
  2138   2140     closeAllCursors(p);
  2139   2141     if( p->magic!=VDBE_MAGIC_RUN ){
  2140   2142       return SQLITE_OK;
  2141   2143     }
  2142   2144     checkActiveVdbeCnt(db);
  2143   2145   
  2144   2146     /* No commit or rollback needed if the program never started */