/ Check-in [44e1c337]
Login

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

Overview
Comment:Change the MEM_Dyn flag so that it means that Mem.xDel exists and must be used to free the string or blob. Add tighter invariant checks on Mem.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | enhanced-mem-check
Files: files | file ages | folders
SHA1: 44e1c33767cae3bf2cbd2238831fe67197009b43
User & Date: drh 2014-03-01 18:13:23
Context
2014-03-03
00:12
Change the MEM_Dyn flag so that it means that Mem.xDel exists and must be used to free the string or blob. Add tighter invariant checks on Mem. check-in: e3f6c61e user: drh tags: trunk
2014-03-01
18:13
Change the MEM_Dyn flag so that it means that Mem.xDel exists and must be used to free the string or blob. Add tighter invariant checks on Mem. Closed-Leaf check-in: 44e1c337 user: drh tags: enhanced-mem-check
16:24
Factor the Mem invariant checker into a separate procedure (rather than a macro) so that it can be more easily extended. check-in: 354699d5 user: drh tags: enhanced-mem-check
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/utf.c.

   313    313     }
   314    314     *z = 0;
   315    315     assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
   316    316   
   317    317     sqlite3VdbeMemRelease(pMem);
   318    318     pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
   319    319     pMem->enc = desiredEnc;
   320         -  pMem->flags |= (MEM_Term|MEM_Dyn);
          320  +  pMem->flags |= (MEM_Term);
   321    321     pMem->z = (char*)zOut;
   322    322     pMem->zMalloc = pMem->z;
   323    323   
   324    324   translate_out:
   325    325   #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
   326    326     {
   327    327       char zBuf[100];
................................................................................
   441    441     sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
   442    442     if( db->mallocFailed ){
   443    443       sqlite3VdbeMemRelease(&m);
   444    444       m.z = 0;
   445    445     }
   446    446     assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
   447    447     assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
   448         -  assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
   449    448     assert( m.z || db->mallocFailed );
   450    449     return m.z;
   451    450   }
   452    451   
   453    452   /*
   454    453   ** zIn is a UTF-16 encoded unicode string at least nChar characters long.
   455    454   ** Return the number of bytes in the first nChar unicode characters

Changes to src/vdbe.c.

   148    148   ** a pointer to a dynamically allocated string where some other entity
   149    149   ** is responsible for deallocating that string.  Because the register
   150    150   ** does not control the string, it might be deleted without the register
   151    151   ** knowing it.
   152    152   **
   153    153   ** This routine converts an ephemeral string into a dynamically allocated
   154    154   ** string that the register itself controls.  In other words, it
   155         -** converts an MEM_Ephem string into an MEM_Dyn string.
          155  +** converts an MEM_Ephem string into a string with P.z==P.zMalloc.
   156    156   */
   157    157   #define Deephemeralize(P) \
   158    158      if( ((P)->flags&MEM_Ephem)!=0 \
   159    159          && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
   160    160   
   161    161   /* Return true if the cursor was opened using the OP_OpenSorter opcode. */
   162    162   #define isSorter(x) ((x)->pSorter!=0)
................................................................................
   712    712   **
   713    713   ** Write the current address onto register P1
   714    714   ** and then jump to address P2.
   715    715   */
   716    716   case OP_Gosub: {            /* jump */
   717    717     assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
   718    718     pIn1 = &aMem[pOp->p1];
   719         -  assert( (pIn1->flags & MEM_Dyn)==0 );
          719  +  assert( VdbeMemDynamic(pIn1)==0 );
   720    720     memAboutToChange(p, pIn1);
   721    721     pIn1->flags = MEM_Int;
   722    722     pIn1->u.i = pc;
   723    723     REGISTER_TRACE(pOp->p1, pIn1);
   724    724     pc = pOp->p2 - 1;
   725    725     break;
   726    726   }
................................................................................
   785    785   ** If the co-routine ends with OP_Yield or OP_Return then continue
   786    786   ** to the next instruction.  But if the co-routine ends with
   787    787   ** OP_EndCoroutine, jump immediately to P2.
   788    788   */
   789    789   case OP_Yield: {            /* in1, jump */
   790    790     int pcDest;
   791    791     pIn1 = &aMem[pOp->p1];
   792         -  assert( (pIn1->flags & MEM_Dyn)==0 );
          792  +  assert( VdbeMemDynamic(pIn1)==0 );
   793    793     pIn1->flags = MEM_Int;
   794    794     pcDest = (int)pIn1->u.i;
   795    795     pIn1->u.i = pc;
   796    796     REGISTER_TRACE(pOp->p1, pIn1);
   797    797     pc = pcDest;
   798    798     break;
   799    799   }
................................................................................
   958    958   
   959    959   #ifndef SQLITE_OMIT_UTF16
   960    960     if( encoding!=SQLITE_UTF8 ){
   961    961       rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
   962    962       if( rc==SQLITE_TOOBIG ) goto too_big;
   963    963       if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
   964    964       assert( pOut->zMalloc==pOut->z );
   965         -    assert( pOut->flags & MEM_Dyn );
          965  +    assert( VdbeMemDynamic(pOut)==0 );
   966    966       pOut->zMalloc = 0;
   967    967       pOut->flags |= MEM_Static;
   968         -    pOut->flags &= ~MEM_Dyn;
   969    968       if( pOp->p4type==P4_DYNAMIC ){
   970    969         sqlite3DbFree(db, pOp->p4.z);
   971    970       }
   972    971       pOp->p4type = P4_DYNAMIC;
   973    972       pOp->p4.z = pOut->z;
   974    973       pOp->p1 = pOut->n;
   975    974     }
................................................................................
  1097   1096     pIn1 = &aMem[p1];
  1098   1097     pOut = &aMem[p2];
  1099   1098     do{
  1100   1099       assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
  1101   1100       assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
  1102   1101       assert( memIsValid(pIn1) );
  1103   1102       memAboutToChange(p, pOut);
         1103  +    VdbeMemRelease(pOut);
  1104   1104       zMalloc = pOut->zMalloc;
  1105         -    pOut->zMalloc = 0;
  1106         -    sqlite3VdbeMemMove(pOut, pIn1);
         1105  +    memcpy(pOut, pIn1, sizeof(Mem));
  1107   1106   #ifdef SQLITE_DEBUG
  1108   1107       if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){
  1109   1108         pOut->pScopyFrom += p1 - pOp->p2;
  1110   1109       }
  1111   1110   #endif
         1111  +    pIn1->flags = MEM_Undefined;
         1112  +    pIn1->xDel = 0;
  1112   1113       pIn1->zMalloc = zMalloc;
  1113   1114       REGISTER_TRACE(p2++, pOut);
  1114   1115       pIn1++;
  1115   1116       pOut++;
  1116   1117     }while( n-- );
  1117   1118     break;
  1118   1119   }
................................................................................
  1281   1282     if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem;
  1282   1283     Stringify(pIn1, encoding);
  1283   1284     Stringify(pIn2, encoding);
  1284   1285     nByte = pIn1->n + pIn2->n;
  1285   1286     if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
  1286   1287       goto too_big;
  1287   1288     }
  1288         -  MemSetTypeFlag(pOut, MEM_Str);
  1289   1289     if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){
  1290   1290       goto no_mem;
  1291   1291     }
         1292  +  MemSetTypeFlag(pOut, MEM_Str);
  1292   1293     if( pOut!=pIn2 ){
  1293   1294       memcpy(pOut->z, pIn2->z, pIn2->n);
  1294   1295     }
  1295   1296     memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n);
  1296   1297     pOut->z[nByte]=0;
  1297   1298     pOut->z[nByte+1] = 0;
  1298   1299     pOut->flags |= MEM_Term;
................................................................................
  2497   2498       sqlite3VdbeSerialGet(zData, t, pDest);
  2498   2499       /* If we dynamically allocated space to hold the data (in the
  2499   2500       ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
  2500   2501       ** dynamically allocated space over to the pDest structure.
  2501   2502       ** This prevents a memory copy. */
  2502   2503       if( sMem.zMalloc ){
  2503   2504         assert( sMem.z==sMem.zMalloc );
  2504         -      assert( !(pDest->flags & MEM_Dyn) );
  2505         -      assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
         2505  +      assert( VdbeMemDynamic(pDest)==0 );
         2506  +      assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z );
  2506   2507         pDest->flags &= ~(MEM_Ephem|MEM_Static);
  2507   2508         pDest->flags |= MEM_Term;
  2508   2509         pDest->z = sMem.z;
  2509   2510         pDest->zMalloc = sMem.zMalloc;
  2510   2511       }
  2511   2512     }
  2512   2513     pDest->enc = encoding;
................................................................................
  2681   2682       j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
  2682   2683     }while( (++pRec)<=pLast );
  2683   2684     assert( i==nHdr );
  2684   2685     assert( j==nByte );
  2685   2686   
  2686   2687     assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
  2687   2688     pOut->n = (int)nByte;
  2688         -  pOut->flags = MEM_Blob | MEM_Dyn;
         2689  +  pOut->flags = MEM_Blob;
  2689   2690     pOut->xDel = 0;
  2690   2691     if( nZero ){
  2691   2692       pOut->u.nZero = nZero;
  2692   2693       pOut->flags |= MEM_Zero;
  2693   2694     }
  2694   2695     pOut->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
  2695   2696     REGISTER_TRACE(pOp->p3, pOut);

Changes to src/vdbeInt.h.

   204    204   
   205    205   /* Whenever Mem contains a valid string or blob representation, one of
   206    206   ** the following flags must be set to determine the memory management
   207    207   ** policy for Mem.z.  The MEM_Term flag tells us whether or not the
   208    208   ** string is \000 or \u0000 terminated
   209    209   */
   210    210   #define MEM_Term      0x0200   /* String rep is nul terminated */
   211         -#define MEM_Dyn       0x0400   /* Need to call sqliteFree() on Mem.z */
          211  +#define MEM_Dyn       0x0400   /* Need to call Mem.xDel() on Mem.z */
   212    212   #define MEM_Static    0x0800   /* Mem.z points to a static string */
   213    213   #define MEM_Ephem     0x1000   /* Mem.z points to an ephemeral string */
   214    214   #define MEM_Agg       0x2000   /* Mem.z points to an agg function context */
   215    215   #define MEM_Zero      0x4000   /* Mem.i contains count of 0s appended to blob */
   216    216   #ifdef SQLITE_OMIT_INCRBLOB
   217    217     #undef MEM_Zero
   218    218     #define MEM_Zero 0x0000

Changes to src/vdbeaux.c.

  1410   1410       pMem->memType = MEM_Int;
  1411   1411       pMem++;
  1412   1412   
  1413   1413       if( sqlite3VdbeMemGrow(pMem, 32, 0) ){            /* P4 */
  1414   1414         assert( p->db->mallocFailed );
  1415   1415         return SQLITE_ERROR;
  1416   1416       }
  1417         -    pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
         1417  +    pMem->flags = MEM_Str|MEM_Term;
  1418   1418       zP4 = displayP4(pOp, pMem->z, 32);
  1419   1419       if( zP4!=pMem->z ){
  1420   1420         sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
  1421   1421       }else{
  1422   1422         assert( pMem->z!=0 );
  1423   1423         pMem->n = sqlite3Strlen30(pMem->z);
  1424   1424         pMem->enc = SQLITE_UTF8;
................................................................................
  1427   1427       pMem++;
  1428   1428   
  1429   1429       if( p->explain==1 ){
  1430   1430         if( sqlite3VdbeMemGrow(pMem, 4, 0) ){
  1431   1431           assert( p->db->mallocFailed );
  1432   1432           return SQLITE_ERROR;
  1433   1433         }
  1434         -      pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
         1434  +      pMem->flags = MEM_Str|MEM_Term;
  1435   1435         pMem->n = 2;
  1436   1436         sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5);   /* P5 */
  1437   1437         pMem->memType = MEM_Str;
  1438   1438         pMem->enc = SQLITE_UTF8;
  1439   1439         pMem++;
  1440   1440     
  1441   1441   #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
  1442   1442         if( sqlite3VdbeMemGrow(pMem, 500, 0) ){
  1443   1443           assert( p->db->mallocFailed );
  1444   1444           return SQLITE_ERROR;
  1445   1445         }
  1446         -      pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
         1446  +      pMem->flags = MEM_Str|MEM_Term;
  1447   1447         pMem->n = displayComment(pOp, zP4, pMem->z, 500);
  1448   1448         pMem->memType = MEM_Str;
  1449   1449         pMem->enc = SQLITE_UTF8;
  1450   1450   #else
  1451   1451         pMem->flags = MEM_Null;                       /* Comment */
  1452   1452         pMem->memType = MEM_Null;
  1453   1453   #endif

Changes to src/vdbemem.c.

    22     22   /*
    23     23   ** Check invariants on a Mem object.
    24     24   **
    25     25   ** This routine is intended for use inside of assert() statements, like
    26     26   ** this:    assert( sqlite3VdbeCheckMemInvariants(pMem) );
    27     27   */
    28     28   int sqlite3VdbeCheckMemInvariants(Mem *p){
    29         -  assert( 
    30         -    (((p)->zMalloc && (p)->zMalloc==(p)->z) ? 1 : 0) +
    31         -    ((((p)->flags&MEM_Dyn)&&(p)->xDel) ? 1 : 0) +
    32         -    (((p)->flags&MEM_Ephem) ? 1 : 0) +
    33         -    (((p)->flags&MEM_Static) ? 1 : 0) <= 1 );
           29  +  /* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor
           30  +  ** function for Mem.z 
           31  +  */
           32  +  assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
           33  +  assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 );
           34  +
           35  +  /* If p holds a string or blob, the Mem.z must point to exactly
           36  +  ** one of the following:
           37  +  **
           38  +  **   (1) Memory in Mem.zMalloc and managed by the Mem object
           39  +  **   (2) Memory to be freed using Mem.xDel
           40  +  **   (3) An ephermal string or blob
           41  +  **   (4) A static string or blob
           42  +  */
           43  +  if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){
           44  +    assert( 
           45  +      ((p->z==p->zMalloc)? 1 : 0) +
           46  +      ((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
           47  +      ((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
           48  +      ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1
           49  +    );
           50  +  }
           51  +
    34     52     return 1;
    35     53   }
    36     54   #endif
    37     55   
    38     56   
    39     57   /*
    40     58   ** If pMem is an object with a valid string representation, this routine
................................................................................
    99    117         pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
   100    118         bPreserve = 0;
   101    119       }else{
   102    120         sqlite3DbFree(pMem->db, pMem->zMalloc);
   103    121         pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
   104    122       }
   105    123       if( pMem->zMalloc==0 ){
   106         -      sqlite3VdbeMemRelease(pMem);
          124  +      VdbeMemRelease(pMem);
   107    125         pMem->flags = MEM_Null;  
   108    126         return SQLITE_NOMEM;
   109    127       }
   110    128     }
   111    129   
   112    130     if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){
   113    131       memcpy(pMem->zMalloc, pMem->z, pMem->n);
   114    132     }
   115         -  if( (pMem->flags&MEM_Dyn)!=0 && pMem->xDel ){
   116         -    assert( pMem->xDel!=SQLITE_DYNAMIC );
          133  +  if( (pMem->flags&MEM_Dyn)!=0 ){
          134  +    assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC );
   117    135       pMem->xDel((void *)(pMem->z));
   118    136     }
   119    137   
   120    138     pMem->z = pMem->zMalloc;
   121         -  pMem->flags &= ~(MEM_Ephem|MEM_Static);
          139  +  pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static);
   122    140     pMem->xDel = 0;
   123    141     return SQLITE_OK;
   124    142   }
   125    143   
   126    144   /*
   127    145   ** Make the given Mem object MEM_Dyn.  In other words, make it so
   128    146   ** that any TEXT or BLOB content is stored in memory obtained from
................................................................................
   283    301   */
   284    302   void sqlite3VdbeMemReleaseExternal(Mem *p){
   285    303     assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
   286    304     if( p->flags&MEM_Agg ){
   287    305       sqlite3VdbeMemFinalize(p, p->u.pDef);
   288    306       assert( (p->flags & MEM_Agg)==0 );
   289    307       sqlite3VdbeMemRelease(p);
   290         -  }else if( p->flags&MEM_Dyn && p->xDel ){
          308  +  }else if( p->flags&MEM_Dyn ){
   291    309       assert( (p->flags&MEM_RowSet)==0 );
   292         -    assert( p->xDel!=SQLITE_DYNAMIC );
          310  +    assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
   293    311       p->xDel((void *)p->z);
   294    312       p->xDel = 0;
   295    313     }else if( p->flags&MEM_RowSet ){
   296    314       sqlite3RowSetClear(p->u.pRowSet);
   297    315     }else if( p->flags&MEM_Frame ){
   298    316       sqlite3VdbeMemSetNull(p);
   299    317     }
................................................................................
   639    657   int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
   640    658     int rc = SQLITE_OK;
   641    659   
   642    660     assert( (pFrom->flags & MEM_RowSet)==0 );
   643    661     VdbeMemRelease(pTo);
   644    662     memcpy(pTo, pFrom, MEMCELLSIZE);
   645    663     pTo->flags &= ~MEM_Dyn;
          664  +  pTo->xDel = 0;
   646    665   
   647    666     if( pTo->flags&(MEM_Str|MEM_Blob) ){
   648    667       if( 0==(pFrom->flags&MEM_Static) ){
   649    668         pTo->flags |= MEM_Ephem;
   650    669         rc = sqlite3VdbeMemMakeWriteable(pTo);
   651    670       }
   652    671     }
................................................................................
   918    937     assert( zData!=0 );
   919    938   
   920    939     if( offset+amt<=available ){
   921    940       sqlite3VdbeMemRelease(pMem);
   922    941       pMem->z = &zData[offset];
   923    942       pMem->flags = MEM_Blob|MEM_Ephem;
   924    943     }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
   925         -    pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
          944  +    pMem->flags = MEM_Blob|MEM_Term;
   926    945       pMem->enc = 0;
   927    946       pMem->memType = MEM_Blob;
   928    947       if( key ){
   929    948         rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
   930    949       }else{
   931    950         rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
   932    951       }