/ Check-in [9f80b268]
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:Fix a crash that can occur following an OOM fault.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sqlite_stat4
Files: files | file ages | folders
SHA1: 9f80b2687012ab7c4d6d654fe19f40878bd78bd8
User & Date: dan 2013-08-15 18:43:21
Context
2013-08-15
19:56
Fix a crash that can occur if the sqlite_stat3 or sqlite_stat4 table is corrupt. check-in: d51df8a8 user: dan tags: sqlite_stat4
18:43
Fix a crash that can occur following an OOM fault. check-in: 9f80b268 user: dan tags: sqlite_stat4
16:18
Change some assert() statements in vdbe.c to ensure that a memory cell used to store a VdbeCursor object is not also used for some other purpose. check-in: 71070c9f user: dan tags: sqlite_stat4
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbemem.c.

  1002   1002       p->type = SQLITE_NULL;
  1003   1003       p->db = db;
  1004   1004     }
  1005   1005     return p;
  1006   1006   }
  1007   1007   
  1008   1008   /*
  1009         -** Argument pCtx is actually a pointer to a database handle. Allocate and
  1010         -** return an sqlite3_value object associated with this database handle.
         1009  +** Context object passed by sqlite3Stat4ProbeSetValue() through to 
         1010  +** valueNew(). See comments above valueNew() for details.
         1011  +*/
         1012  +struct ValueNewStat4Ctx {
         1013  +  Parse *pParse;
         1014  +  Index *pIdx;
         1015  +  UnpackedRecord **ppRec;
         1016  +  int iVal;
         1017  +};
         1018  +
         1019  +/*
         1020  +** Allocate and return a pointer to a new sqlite3_value object. If
         1021  +** the second argument to this function is NULL, the object is allocated
         1022  +** by calling sqlite3ValueNew().
  1011   1023   **
  1012         -** This function used as the xAlloc callback for valueFromExpr() when
  1013         -** it is called by sqlite3ValueFromExpr().
         1024  +** Otherwise, if the second argument is non-zero, then this function is 
         1025  +** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
         1026  +** already been allocated, allocate the UnpackedRecord structure that 
         1027  +** that function will return to its caller here. Then return a pointer 
         1028  +** an sqlite3_value within the UnpackedRecord.a[] array.
  1014   1029   */
  1015         -static sqlite3_value *valueNew(void *pCtx){
  1016         -  return sqlite3ValueNew((sqlite3*)pCtx);
         1030  +static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
         1031  +#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
         1032  +  if( p ){
         1033  +    UnpackedRecord *pRec = p->ppRec[0];
         1034  +
         1035  +    if( pRec==0 ){
         1036  +      Index *pIdx = p->pIdx;      /* Index being probed */
         1037  +      int nByte;                  /* Bytes of space to allocate */
         1038  +      int i;                      /* Counter variable */
         1039  +      int nCol = pIdx->nColumn+1; /* Number of index columns including rowid */
         1040  +  
         1041  +      nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord);
         1042  +      pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
         1043  +      if( pRec ){
         1044  +        pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx);
         1045  +        if( pRec->pKeyInfo ){
         1046  +          assert( pRec->pKeyInfo->nField+1==nCol );
         1047  +          pRec->pKeyInfo->enc = ENC(db);
         1048  +          pRec->flags = UNPACKED_PREFIX_MATCH;
         1049  +          pRec->aMem = (Mem *)&pRec[1];
         1050  +          for(i=0; i<nCol; i++){
         1051  +            pRec->aMem[i].flags = MEM_Null;
         1052  +            pRec->aMem[i].type = SQLITE_NULL;
         1053  +            pRec->aMem[i].db = db;
         1054  +          }
         1055  +        }else{
         1056  +          sqlite3DbFree(db, pRec);
         1057  +          pRec = 0;
         1058  +        }
         1059  +      }
         1060  +      if( pRec==0 ) return 0;
         1061  +      p->ppRec[0] = pRec;
         1062  +    }
         1063  +  
         1064  +    pRec->nField = p->iVal+1;
         1065  +    return &pRec->aMem[p->iVal];
         1066  +  }
         1067  +#endif
         1068  +  return sqlite3ValueNew(db);
  1017   1069   }
  1018   1070   
  1019   1071   /*
  1020         -** This function is the same as sqlite3ValueFromExpr(), except that instead
  1021         -** of allocating any required sqlite3_value object by calling 
  1022         -** sqlite3ValueNew(), it does so by calling the supplied xAlloc hook. 
         1072  +** Extract a value from the supplied expression in the manner described
         1073  +** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
         1074  +** using valueNew().
         1075  +**
         1076  +** If pCtx is NULL and an error occurs after the sqlite3_value object
         1077  +** has been allocated, it is freed before returning. Or, if pCtx is not
         1078  +** NULL, it is assumed that the caller will free any allocated object
         1079  +** in all cases.
  1023   1080   */
  1024   1081   int valueFromExpr(
  1025         -  sqlite3 *db,                         /* The database connection */
  1026         -  Expr *pExpr,                         /* The expression to evaluate */
  1027         -  u8 enc,                              /* Encoding to use */
  1028         -  u8 affinity,                         /* Affinity to use */
  1029         -  sqlite3_value **ppVal,               /* Write the new value here */
  1030         -  sqlite3_value *(*xAlloc)(void*),     /* Used to allocate new sqlite3_value */
  1031         -  void *pAlloc                         /* Argument passed to xAlloc */
         1082  +  sqlite3 *db,                    /* The database connection */
         1083  +  Expr *pExpr,                    /* The expression to evaluate */
         1084  +  u8 enc,                         /* Encoding to use */
         1085  +  u8 affinity,                    /* Affinity to use */
         1086  +  sqlite3_value **ppVal,          /* Write the new value here */
         1087  +  struct ValueNewStat4Ctx *pCtx   /* Second argument for valueNew() */
  1032   1088   ){
  1033   1089     int op;
  1034   1090     char *zVal = 0;
  1035   1091     sqlite3_value *pVal = 0;
  1036   1092     int negInt = 1;
  1037   1093     const char *zNeg = "";
  1038   1094   
................................................................................
  1060   1116       pExpr = pExpr->pLeft;
  1061   1117       op = pExpr->op;
  1062   1118       negInt = -1;
  1063   1119       zNeg = "-";
  1064   1120     }
  1065   1121   
  1066   1122     if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
  1067         -    pVal = xAlloc(pAlloc);
         1123  +    pVal = valueNew(db, pCtx);
  1068   1124       if( pVal==0 ) goto no_mem;
  1069   1125       if( ExprHasProperty(pExpr, EP_IntValue) ){
  1070   1126         sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
  1071   1127       }else{
  1072   1128         zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
  1073   1129         if( zVal==0 ) goto no_mem;
  1074   1130         sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
................................................................................
  1096   1152         }else{
  1097   1153           pVal->u.i = -pVal->u.i;
  1098   1154         }
  1099   1155         pVal->r = -pVal->r;
  1100   1156         sqlite3ValueApplyAffinity(pVal, affinity, enc);
  1101   1157       }
  1102   1158     }else if( op==TK_NULL ){
  1103         -    pVal = xAlloc(pAlloc);
         1159  +    pVal = valueNew(db, pCtx);
  1104   1160       if( pVal==0 ) goto no_mem;
  1105   1161     }
  1106   1162   #ifndef SQLITE_OMIT_BLOB_LITERAL
  1107   1163     else if( op==TK_BLOB ){
  1108   1164       int nVal;
  1109   1165       assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
  1110   1166       assert( pExpr->u.zToken[1]=='\'' );
  1111         -    pVal = xAlloc(pAlloc);
         1167  +    pVal = valueNew(db, pCtx);
  1112   1168       if( !pVal ) goto no_mem;
  1113   1169       zVal = &pExpr->u.zToken[2];
  1114   1170       nVal = sqlite3Strlen30(zVal)-1;
  1115   1171       assert( zVal[nVal]=='\'' );
  1116   1172       sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
  1117   1173                            0, SQLITE_DYNAMIC);
  1118   1174     }
................................................................................
  1123   1179     }
  1124   1180     *ppVal = pVal;
  1125   1181     return SQLITE_OK;
  1126   1182   
  1127   1183   no_mem:
  1128   1184     db->mallocFailed = 1;
  1129   1185     sqlite3DbFree(db, zVal);
  1130         -  if( *ppVal==0 ) sqlite3ValueFree(pVal);
  1131         -  *ppVal = 0;
         1186  +  assert( *ppVal==0 );
         1187  +  if( pCtx==0 ) sqlite3ValueFree(pVal);
  1132   1188     return SQLITE_NOMEM;
  1133   1189   }
  1134   1190   
  1135   1191   /*
  1136   1192   ** Create a new sqlite3_value object, containing the value of pExpr.
  1137   1193   **
  1138   1194   ** This only works for very simple expressions that consist of one constant
................................................................................
  1145   1201   int sqlite3ValueFromExpr(
  1146   1202     sqlite3 *db,              /* The database connection */
  1147   1203     Expr *pExpr,              /* The expression to evaluate */
  1148   1204     u8 enc,                   /* Encoding to use */
  1149   1205     u8 affinity,              /* Affinity to use */
  1150   1206     sqlite3_value **ppVal     /* Write the new value here */
  1151   1207   ){
  1152         -  return valueFromExpr(db, pExpr, enc, affinity, ppVal, valueNew, (void*)db);
         1208  +  return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0);
  1153   1209   }
  1154   1210   
  1155   1211   #if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3)
  1156   1212   /*
  1157   1213   ** The implementation of the sqlite_record() function. This function accepts
  1158   1214   ** a single argument of any type. The return value is a formatted database 
  1159   1215   ** record (a blob) containing the argument value.
................................................................................
  1203   1259     FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
  1204   1260     FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
  1205   1261     for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
  1206   1262       sqlite3FuncDefInsert(pHash, &aFunc[i]);
  1207   1263     }
  1208   1264   }
  1209   1265   
  1210         -/*
  1211         -** A pointer to an instance of this object is passed as the context 
  1212         -** pointer to valueNewStat4() (see below.
  1213         -*/
  1214         -struct ValueNewStat4Ctx {
  1215         -  Parse *pParse;
  1216         -  Index *pIdx;
  1217         -  UnpackedRecord **ppRec;
  1218         -  int iVal;
  1219         -};
  1220         -
  1221         -/*
  1222         -** This function is used as the xAlloc function with valueFromExpr() when
  1223         -** it is called by sqlite3Stat4ProbeSetValue(). The argument points to
  1224         -** an object of type ValueNewStat4Ctx (see above).
  1225         -**
  1226         -** If it has not already been allocated, this function allocates an 
  1227         -** UnpackedRecord structure and space for up to N values, where N is the
  1228         -** number of columns in the index being probed.
  1229         -*/
  1230         -static sqlite3_value *valueNewStat4(void *pCtx){
  1231         -  struct ValueNewStat4Ctx *p = (struct ValueNewStat4Ctx*)pCtx;
  1232         -  UnpackedRecord *pRec = p->ppRec[0];
  1233         -
  1234         -  if( pRec==0 ){
  1235         -    sqlite3 *db = p->pParse->db;  /* Database handle */
  1236         -    Index *pIdx = p->pIdx;        /* Index being probed */
  1237         -    int nByte;                    /* Bytes of space to allocate */
  1238         -    int i;                        /* Counter variable */
  1239         -    int nCol = pIdx->nColumn+1;   /* Number of index columns including rowid */
  1240         -
  1241         -    nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord);
  1242         -    pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
  1243         -    if( pRec ){
  1244         -      pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx);
  1245         -      if( pRec->pKeyInfo ){
  1246         -        assert( pRec->pKeyInfo->nField+1==nCol );
  1247         -        pRec->pKeyInfo->enc = ENC(db);
  1248         -        pRec->flags = UNPACKED_PREFIX_MATCH;
  1249         -        pRec->aMem = (Mem *)&pRec[1];
  1250         -        for(i=0; i<nCol; i++){
  1251         -          pRec->aMem[i].flags = MEM_Null;
  1252         -          pRec->aMem[i].type = SQLITE_NULL;
  1253         -          pRec->aMem[i].db = db;
  1254         -        }
  1255         -      }else{
  1256         -        sqlite3DbFree(db, pRec);
  1257         -        pRec = 0;
  1258         -      }
  1259         -    }
  1260         -    if( pRec==0 ) return 0;
  1261         -    p->ppRec[0] = pRec;
  1262         -  }
  1263         -
  1264         -  pRec->nField = p->iVal+1;
  1265         -  return &pRec->aMem[p->iVal];
  1266         -}
  1267         -
  1268   1266   /*
  1269   1267   ** This function is used to allocate and populate UnpackedRecord 
  1270   1268   ** structures intended to be compared against sample index keys stored 
  1271   1269   ** in the sqlite_stat4 table.
  1272   1270   **
  1273   1271   ** A single call to this function attempts to populates field iVal (leftmost 
  1274   1272   ** is 0 etc.) of the unpacked record with a value extracted from expression
................................................................................
  1309   1307   
  1310   1308     struct ValueNewStat4Ctx alloc;
  1311   1309     alloc.pParse = pParse;
  1312   1310     alloc.pIdx = pIdx;
  1313   1311     alloc.ppRec = ppRec;
  1314   1312     alloc.iVal = iVal;
  1315   1313   
  1316         -#if 0
  1317         -  if( iVal>0 ){ *pbOk = 0; return SQLITE_OK; }
  1318         -#endif
  1319         -
  1320   1314     if( !pExpr ){
  1321         -    pVal = valueNewStat4((void*)&alloc);
         1315  +    pVal = valueNew(pParse->db, &alloc);
  1322   1316       if( pVal ){
  1323   1317         sqlite3VdbeMemSetNull((Mem*)pVal);
  1324   1318         *pbOk = 1;
  1325   1319       }
  1326   1320     }else if( pExpr->op==TK_VARIABLE
  1327   1321           || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
  1328   1322     ){
  1329   1323       Vdbe *v;
  1330   1324       int iVar = pExpr->iColumn;
  1331   1325       sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
  1332   1326       if( (v = pParse->pReprepare) ){
  1333         -      pVal = valueNewStat4((void*)&alloc);
         1327  +      pVal = valueNew(pParse->db, &alloc);
  1334   1328         if( pVal ){
  1335   1329           rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iVal-1]);
  1336   1330           if( rc==SQLITE_OK ){
  1337   1331             sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
  1338   1332           }
  1339   1333           pVal->db = pParse->db;
  1340   1334           *pbOk = 1;
................................................................................
  1341   1335           sqlite3VdbeMemStoreType((Mem*)pVal);
  1342   1336         }
  1343   1337       }else{
  1344   1338         *pbOk = 0;
  1345   1339       }
  1346   1340     }else{
  1347   1341       sqlite3 *db = pParse->db;
  1348         -    rc = valueFromExpr(
  1349         -        db, pExpr, ENC(db), affinity, &pVal, valueNewStat4, (void*)&alloc
  1350         -    );
         1342  +    rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc);
  1351   1343       *pbOk = (pVal!=0);
  1352   1344     }
  1353   1345   
  1354   1346     assert( pVal==0 || pVal->db==pParse->db );
  1355   1347     return rc;
  1356   1348   }
  1357   1349   

Changes to test/analyze9.test.

   251    251   
   252    252   # Check that the perioidic samples are present.
   253    253   do_execsql_test 4.6 {
   254    254     SELECT count(*) FROM sqlite_stat4
   255    255     WHERE lindex(test_decode(sample), 3) IN 
   256    256       ('34', '68', '102', '136', '170', '204', '238', '272')
   257    257   } {8}
          258  +
          259  +reset_db
          260  +do_test 4.7 {
          261  +  execsql { 
          262  +    BEGIN;
          263  +    CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
          264  +    CREATE INDEX i1 ON t1(o);
          265  +  }
          266  +  for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
          267  +    execsql { INSERT INTO t1 VALUES('x', $i) }
          268  +  }
          269  +  execsql {
          270  +    COMMIT;
          271  +    ANALYZE;
          272  +    SELECT count(*) FROM sqlite_stat4;
          273  +  }
          274  +} {8}
          275  +do_execsql_test 4.8 {
          276  +  SELECT test_decode(sample) FROM sqlite_stat4;
          277  +} {
          278  +  {x 211} {x 423} {x 635} {x 847} 
          279  +  {x 1590} {x 3710} {x 5830} {x 7950}
          280  +}
          281  +
   258    282   
   259    283   #-------------------------------------------------------------------------
   260    284   # The following would cause a crash at one point.
   261    285   #
   262    286   reset_db
   263    287   do_execsql_test 5.1 {
   264    288     PRAGMA encoding = 'utf-16';
   265    289     CREATE TABLE t0(v);
   266    290     ANALYZE;
   267    291   }
   268    292   
   269    293   finish_test
   270    294   

Changes to test/mallocA.test.

    11     11   # This file contains additional out-of-memory checks (see malloc.tcl).
    12     12   #
    13     13   # $Id: mallocA.test,v 1.8 2008/02/18 22:24:58 drh Exp $
    14     14   
    15     15   set testdir [file dirname $argv0]
    16     16   source $testdir/tester.tcl
    17     17   source $testdir/malloc_common.tcl
           18  +set testprefix mallocA
    18     19   
    19     20   # Only run these tests if memory debugging is turned on.
    20     21   #
    21     22   if {!$MEMDEBUG} {
    22     23      puts "Skipping mallocA tests: not compiled with -DSQLITE_MEMDEBUG..."
    23     24      finish_test
    24     25      return
................................................................................
    36     37     CREATE INDEX t1i1 ON t1(a);
    37     38     CREATE INDEX t1i2 ON t1(b,c);
    38     39     CREATE TABLE t2(x,y,z);
    39     40   }
    40     41   db close
    41     42   copy_file test.db test.db.bu
    42     43   
    43         -
    44     44   do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody {
    45     45     ANALYZE
    46     46   }
    47     47   do_malloc_test mallocA-1.1 -testdb test.db.bu -sqlbody {
    48     48     ANALYZE t1
    49     49   }
    50     50   do_malloc_test mallocA-1.2 -testdb test.db.bu -sqlbody {
    51     51     ANALYZE main
    52     52   }
    53     53   do_malloc_test mallocA-1.3 -testdb test.db.bu -sqlbody {
    54     54     ANALYZE main.t1
    55     55   }
           56  +
    56     57   ifcapable reindex {
    57     58     do_malloc_test mallocA-2 -testdb test.db.bu -sqlbody {
    58     59       REINDEX;
    59     60     }
    60     61     do_malloc_test mallocA-3 -testdb test.db.bu -sqlbody {
    61     62       REINDEX t1;
    62     63     }
................................................................................
    63     64     do_malloc_test mallocA-4 -testdb test.db.bu -sqlbody {
    64     65       REINDEX main.t1;
    65     66     }
    66     67     do_malloc_test mallocA-5 -testdb test.db.bu -sqlbody {
    67     68       REINDEX nocase;
    68     69     }
    69     70   }
           71  +
           72  +reset_db
           73  +sqlite3_db_config_lookaside db 0 0 0
           74  +do_execsql_test 6-prep {
           75  +  CREATE TABLE t1(a, b);
           76  +  CREATE INDEX i1 ON t1(a, b);
           77  +  INSERT INTO t1 VALUES('abc', 'w'); -- rowid=1
           78  +  INSERT INTO t1 VALUES('abc', 'x'); -- rowid=2
           79  +  INSERT INTO t1 VALUES('abc', 'y'); -- rowid=3
           80  +  INSERT INTO t1 VALUES('abc', 'z'); -- rowid=4
           81  +
           82  +  INSERT INTO t1 VALUES('def', 'w'); -- rowid=5
           83  +  INSERT INTO t1 VALUES('def', 'x'); -- rowid=6
           84  +  INSERT INTO t1 VALUES('def', 'y'); -- rowid=7
           85  +  INSERT INTO t1 VALUES('def', 'z'); -- rowid=8
           86  +
           87  +  ANALYZE;
           88  +}
           89  +
           90  +do_faultsim_test 6.1 -faults oom* -body {
           91  +  execsql { SELECT rowid FROM t1 WHERE a='abc' AND b='x' }
           92  +} -test {
           93  +  faultsim_test_result [list 0 2]
           94  +}
           95  +do_faultsim_test 6.2 -faults oom* -body {
           96  +  execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' }
           97  +} -test {
           98  +  faultsim_test_result [list 0 {1 2}]
           99  +}
    70    100   
    71    101   # Ensure that no file descriptors were leaked.
    72    102   do_test malloc-99.X {
    73    103     catch {db close}
    74    104     set sqlite_open_file_count
    75    105   } {0}
    76    106   
    77    107   forcedelete test.db.bu
    78    108   finish_test