/ Check-in [4ade96ce]
Login

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

Overview
Comment:Fix a case in fts4 where a corrupt %_stat table could lead to a crash.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | fts4aux
Files: files | file ages | folders
SHA1: 4ade96ce974244fc34bb97713d3cba10e3d33056
User & Date: dan 2011-02-01 17:55:48
Context
2011-02-01
18:00
Fix a problem causing builds with SQLITE_OMIT_WAL defined to fail. check-in: b9b48dd8 user: dan tags: fts4aux
17:55
Fix a case in fts4 where a corrupt %_stat table could lead to a crash. check-in: 4ade96ce user: dan tags: fts4aux
16:34
Add virtual table module "fts4aux", used to inspect the full-text index of an fts4 table directly. Also add the "compress" and "uncompress" fts4 options. check-in: b010ddcc user: dan tags: fts4aux
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_snippet.c.

   956    956       if( rc!=SQLITE_OK ) return rc;
   957    957     }
   958    958     pStmt = *ppStmt;
   959    959     assert( sqlite3_data_count(pStmt)==1 );
   960    960   
   961    961     a = sqlite3_column_blob(pStmt, 0);
   962    962     a += sqlite3Fts3GetVarint(a, &nDoc);
          963  +  if( nDoc==0 ) return SQLITE_CORRUPT;
   963    964     *pnDoc = (u32)nDoc;
   964    965   
   965    966     if( paLen ) *paLen = a;
   966    967     return SQLITE_OK;
   967    968   }
   968    969   
   969    970   /*
................................................................................
  1162   1163             sqlite3_int64 nDoc;     /* Number of rows in table */
  1163   1164             const char *a;          /* Aggregate column length array */
  1164   1165   
  1165   1166             rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
  1166   1167             if( rc==SQLITE_OK ){
  1167   1168               int iCol;
  1168   1169               for(iCol=0; iCol<pInfo->nCol; iCol++){
         1170  +              u32 iVal;
  1169   1171                 sqlite3_int64 nToken;
  1170   1172                 a += sqlite3Fts3GetVarint(a, &nToken);
  1171         -              pInfo->aMatchinfo[iCol] = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
         1173  +              iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
         1174  +              pInfo->aMatchinfo[iCol] = iVal;
  1172   1175               }
  1173   1176             }
  1174   1177           }
  1175   1178           break;
  1176   1179   
  1177   1180         case FTS3_MATCHINFO_LENGTH: {
  1178   1181           sqlite3_stmt *pSelectDocsize = 0;

Changes to ext/fts3/fts3_write.c.

   285    285   
   286    286     rc = fts3SqlStmt(pTab, eStmt, &pStmt, 0);
   287    287     if( rc==SQLITE_OK ){
   288    288       if( eStmt==SQL_SELECT_DOCSIZE ){
   289    289         sqlite3_bind_int64(pStmt, 1, iDocid);
   290    290       }
   291    291       rc = sqlite3_step(pStmt);
   292         -    if( rc!=SQLITE_ROW ){
          292  +    if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
   293    293         rc = sqlite3_reset(pStmt);
   294    294         if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT;
   295    295         pStmt = 0;
   296    296       }else{
   297    297         rc = SQLITE_OK;
   298    298       }
   299    299     }
................................................................................
  1098   1098         ** the table. The following nCol varints contain the total amount of
  1099   1099         ** data stored in all rows of each column of the table, from left
  1100   1100         ** to right.
  1101   1101         */
  1102   1102         sqlite3_stmt *pStmt;
  1103   1103         sqlite3_int64 nDoc = 0;
  1104   1104         sqlite3_int64 nByte = 0;
         1105  +      const char *pEnd;
  1105   1106         const char *a;
         1107  +
  1106   1108         rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
  1107         -      if( rc ) return rc;
         1109  +      if( rc!=SQLITE_OK ) return rc;
  1108   1110         a = sqlite3_column_blob(pStmt, 0);
  1109         -      if( a ){
  1110         -        const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
  1111         -        a += sqlite3Fts3GetVarint(a, &nDoc);
  1112         -        while( a<pEnd ){
  1113         -          a += sqlite3Fts3GetVarint(a, &nByte);
  1114         -        }
         1111  +      assert( a );
         1112  +
         1113  +      pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
         1114  +      a += sqlite3Fts3GetVarint(a, &nDoc);
         1115  +      while( a<pEnd ){
         1116  +        a += sqlite3Fts3GetVarint(a, &nByte);
  1115   1117         }
  1116   1118         if( nDoc==0 || nByte==0 ){
  1117   1119           sqlite3_reset(pStmt);
  1118   1120           return SQLITE_CORRUPT;
  1119   1121         }
  1120   1122   
  1121   1123         pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz);

Changes to test/fts3corrupt.test.

   126    126     "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
   127    127   ]
   128    128   
   129    129   do_catchsql_test 4.3 {
   130    130     UPDATE t1_segdir SET root = $blob;
   131    131     SELECT rowid FROM t1 WHERE t1 MATCH 'world';
   132    132   } {1 {database disk image is malformed}}
          133  +
          134  +# Test a special kind of corruption, where the %_stat table contains
          135  +# an invalid entry. At one point this could lead to a division-by-zero
          136  +# error in fts4.
          137  +#
          138  +do_execsql_test 5.0 {
          139  +  DROP TABLE t1;
          140  +  CREATE VIRTUAL TABLE t1 USING fts4;
          141  +}
          142  +do_test 5.1 {
          143  +  db func nn nn
          144  +  execsql BEGIN
          145  +  execsql { INSERT INTO t1 VALUES('one') }
          146  +  execsql { INSERT INTO t1 VALUES('two') }
          147  +  execsql { INSERT INTO t1 VALUES('three') }
          148  +  execsql { INSERT INTO t1 VALUES('four') }
          149  +  execsql COMMIT
          150  +} {}
          151  +do_catchsql_test 5.2 {
          152  +  UPDATE t1_stat SET value = X'0000';
          153  +  SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*';
          154  +} {1 {database disk image is malformed}}
          155  +do_catchsql_test 5.3 {
          156  +  UPDATE t1_stat SET value = NULL;
          157  +  SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*';
          158  +} {1 {database disk image is malformed}}
          159  +
   133    160   
   134    161   finish_test
   135    162