/ Check-in [d0342f4b]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Continuing work toward detecting and fixing shallow-copy misuse.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bug-b351d95f9c
Files: files | file ages | folders
SHA1: d0342f4bb9d25dd1dba3957778faa993fb9cc81c
User & Date: drh 2010-09-28 00:25:59
Context
2010-09-28
03:55
Use OP_Copy rather than OP_SCopy at one point in aggregate processing where it is needed to avoid shallow-copy misuse. check-in: a5eefd52 user: drh tags: bug-b351d95f9c
00:25
Continuing work toward detecting and fixing shallow-copy misuse. check-in: d0342f4b user: drh tags: bug-b351d95f9c
2010-09-27
21:09
Add assert() statements that fail when a shallow copy is accessed after the original has been modified. These assert() statements should detect the kinds of subtle SCopy bugs such as caused the fault in ticket [b351d95f9cd5ef17e9d9dbae18f]. check-in: 8b8e1732 user: drh tags: bug-b351d95f9c
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  2863   2863   ** results in register target.  The results are guaranteed to appear
  2864   2864   ** in register target.
  2865   2865   */
  2866   2866   int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
  2867   2867     int inReg;
  2868   2868   
  2869   2869     assert( target>0 && target<=pParse->nMem );
  2870         -  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
  2871         -  assert( pParse->pVdbe || pParse->db->mallocFailed );
  2872         -  if( inReg!=target && pParse->pVdbe ){
  2873         -    sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
         2870  +  if( pExpr && pExpr->op==TK_REGISTER ){
         2871  +    sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
         2872  +  }else{
         2873  +    inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
         2874  +    assert( pParse->pVdbe || pParse->db->mallocFailed );
         2875  +    if( inReg!=target && pParse->pVdbe ){
         2876  +      sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
         2877  +    }
  2874   2878     }
  2875   2879     return target;
  2876   2880   }
  2877   2881   
  2878   2882   /*
  2879   2883   ** Generate code that evalutes the given expression and puts the result
  2880   2884   ** in register target.

Changes to src/fkey.c.

   376    376         int regTemp = sqlite3GetTempRange(pParse, nCol);
   377    377         int regRec = sqlite3GetTempReg(pParse);
   378    378         KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
   379    379     
   380    380         sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
   381    381         sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
   382    382         for(i=0; i<nCol; i++){
   383         -        sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
          383  +        sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
   384    384         }
   385    385     
   386    386         /* If the parent table is the same as the child table, and we are about
   387    387         ** to increment the constraint-counter (i.e. this is an INSERT operation),
   388    388         ** then check if the row being inserted matches itself. If so, do not
   389    389         ** increment the constraint-counter.  */
   390    390         if( pTab==pFKey->pFrom && nIncr==1 ){

Changes to src/vdbe.c.

  1138   1138     /* Make sure the results of the current row are \000 terminated
  1139   1139     ** and have an assigned type.  The results are de-ephemeralized as
  1140   1140     ** as side effect.
  1141   1141     */
  1142   1142     pMem = p->pResultSet = &aMem[pOp->p1];
  1143   1143     for(i=0; i<pOp->p2; i++){
  1144   1144       assert( memIsValid(&pMem[i]) );
  1145         -    memAboutToChange(p, &pMem[i]);
         1145  +    Deephemeralize(&pMem[i]);
  1146   1146       sqlite3VdbeMemNulTerminate(&pMem[i]);
  1147   1147       sqlite3VdbeMemStoreType(&pMem[i]);
  1148   1148       REGISTER_TRACE(pOp->p1+i, &pMem[i]);
  1149   1149     }
  1150   1150     if( db->mallocFailed ) goto no_mem;
  1151   1151   
  1152   1152     /* Return SQLITE_ROW
................................................................................
  1364   1364     sqlite3_context ctx;
  1365   1365     sqlite3_value **apVal;
  1366   1366     int n;
  1367   1367   
  1368   1368     n = pOp->p5;
  1369   1369     apVal = p->apArg;
  1370   1370     assert( apVal || n==0 );
         1371  +  assert( pOp->p3>0 && pOp->p3<=p->nMem );
         1372  +  pOut = &aMem[pOp->p3];
         1373  +  memAboutToChange(p, pOut);
  1371   1374   
  1372   1375     assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
  1373   1376     assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
  1374   1377     pArg = &aMem[pOp->p2];
  1375   1378     for(i=0; i<n; i++, pArg++){
  1376   1379       assert( memIsValid(pArg) );
  1377   1380       apVal[i] = pArg;
  1378         -    memAboutToChange(p, pArg);
         1381  +    Deephemeralize(pArg);
  1379   1382       sqlite3VdbeMemStoreType(pArg);
  1380   1383       REGISTER_TRACE(pOp->p2+i, pArg);
  1381   1384     }
  1382   1385   
  1383   1386     assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
  1384   1387     if( pOp->p4type==P4_FUNCDEF ){
  1385   1388       ctx.pFunc = pOp->p4.pFunc;
  1386   1389       ctx.pVdbeFunc = 0;
  1387   1390     }else{
  1388   1391       ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
  1389   1392       ctx.pFunc = ctx.pVdbeFunc->pFunc;
  1390   1393     }
  1391   1394   
  1392         -  assert( pOp->p3>0 && pOp->p3<=p->nMem );
  1393         -  pOut = &aMem[pOp->p3];
  1394         -  memAboutToChange(p, pOut);
  1395   1395     ctx.s.flags = MEM_Null;
  1396   1396     ctx.s.db = db;
  1397   1397     ctx.s.xDel = 0;
  1398   1398     ctx.s.zMalloc = 0;
  1399   1399   
  1400   1400     /* The output cell may already have a buffer allocated. Move
  1401   1401     ** the pointer to ctx.s so in case the user-function can use

Changes to src/vdbemem.c.

   128    128     if( (f&(MEM_Str|MEM_Blob)) && pMem->z!=pMem->zMalloc ){
   129    129       if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
   130    130         return SQLITE_NOMEM;
   131    131       }
   132    132       pMem->z[pMem->n] = 0;
   133    133       pMem->z[pMem->n+1] = 0;
   134    134       pMem->flags |= MEM_Term;
          135  +#ifdef SQLITE_DEBUG
          136  +    pMem->pScopyFrom = 0;
          137  +#endif
   135    138     }
   136    139   
   137    140     return SQLITE_OK;
   138    141   }
   139    142   
   140    143   /*
   141    144   ** If the given Mem* has a zero-filled tail, turn it into an ordinary