SQLite

Check-in [84194c41]
Login

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

Overview
Comment:Fix a buffer overread in fts3 that can occur if the database is corrupt.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 84194c4195d7144ff7f9cedcdc74fdd908f3bfcd
User & Date: dan 2010-10-27 16:52:27
Context
2010-10-27
18:10
Merge experimental fts3/fts4 changes with trunk. (check-in: 988164cf user: dan tags: trunk)
16:52
Fix a buffer overread in fts3 that can occur if the database is corrupt. (Closed-Leaf check-in: 84194c41 user: dan tags: experimental)
10:55
In fts4, store the total number of bytes of for all records in the table in the %_stat table. (check-in: 941647d1 user: dan tags: experimental)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_write.c.

912
913
914
915
916
917
918
919
920
921











922
923
924
925
926
927
928
    pReader->zTerm = zNew;
    pReader->nTermAlloc = nNew;
  }
  memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix);
  pReader->nTerm = nPrefix+nSuffix;
  pNext += nSuffix;
  pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist);
  assert( pNext<&pReader->aNode[pReader->nNode] );
  pReader->aDoclist = pNext;
  pReader->pOffsetList = 0;











  return SQLITE_OK;
}

/*
** Set the SegReader to point to the first docid in the doclist associated
** with the current term.
*/







<


>
>
>
>
>
>
>
>
>
>
>







912
913
914
915
916
917
918

919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
    pReader->zTerm = zNew;
    pReader->nTermAlloc = nNew;
  }
  memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix);
  pReader->nTerm = nPrefix+nSuffix;
  pNext += nSuffix;
  pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist);

  pReader->aDoclist = pNext;
  pReader->pOffsetList = 0;

  /* Check that the doclist does not appear to extend past the end of the
  ** b-tree node. And that the final byte of the doclist is either an 0x00 
  ** or 0x01. If either of these statements is untrue, then the data structure 
  ** is corrupt.
  */
  if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] 
   || (pReader->aDoclist[pReader->nDoclist-1]&0xFE)!=0
  ){
    return SQLITE_CORRUPT;
  }
  return SQLITE_OK;
}

/*
** Set the SegReader to point to the first docid in the doclist associated
** with the current term.
*/

Added test/fts3corrupt.test.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 2010 October 27
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# Test that the FTS3 extension does not crash when it encounters a
# corrupt data structure on disk.
#


set testdir [file dirname $argv0]
source $testdir/tester.tcl

# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 { finish_test ; return }

set ::testprefix fts3corrupt

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE t1 USING fts3;
  INSERT INTO t1 VALUES('hello');
} {}

do_test fts3corrupt-1.1 {
  set blob [db one {SELECT root from t1_segdir}]
  set blob [binary format a7ca* $blob 24 [string range $blob 8 end]]
  execsql { UPDATE t1_segdir SET root = $blob }
} {}

do_test fts3corrupt-1.2 {
  foreach w {a b c d e f g h i j k l m n o} {
    execsql { INSERT INTO t1 VALUES($w) }
  }
} {}

do_catchsql_test 1.3 {
  INSERT INTO t1 VALUES('world');
} {1 {database disk image is malformed}}

finish_test

Changes to test/fts3defer2.test.

32
33
34
35
36
37
38





39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
do_execsql_test 1.1.1 {
  CREATE VIRTUAL TABLE t1 USING fts4;
}
do_execsql_test 1.1.2 "INSERT INTO t1 VALUES('[string repeat {a } 20000]')"
do_execsql_test 1.1.3 "INSERT INTO t1 VALUES('[string repeat {z } 20000]')"
do_execsql_test 1.1.4 {
  INSERT INTO t1 VALUES('a b c d e f a x y');





  INSERT INTO t1(t1) VALUES('optimize');
  UPDATE t1_segments 
    SET block = zeroblob(length(block)) 
    WHERE length(block)>10000;
}
do_execsql_test 1.1.4 {
  SELECT count(*) FROM t1_segments WHERE length(block)>10000;
  UPDATE t1_segments 
    SET block = zeroblob(length(block)) WHERE length(block)>10000;
} {2}

do_execsql_test 1.2.1 {
  SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} {{a b c d e f a x y}}

do_execsql_test 1.2.2 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} [list                              \
   {a b c d [e] [f] [a] x y}         \
   {0 1 8 1 0 0 10 1 0 2 12 1}       \
   [list 3 1   1 1 1   1 3 3   1 3 3   3 13336 9]
]

do_execsql_test 1.2.3 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/3 a)';
} [list                                 \
   {[a] b c d [e] [f] [a] x y}          \
   {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
   [list 3 1   1 1 1   1 3 3   2 3 3   3 13336 9]
]

do_execsql_test 1.3.1 { DROP TABLE t1 }

#-----------------------------------------------------------------------------
# Test cases fts3defer2-2.* focus specifically on the matchinfo function.
# 







>
>
>
>
>

<
<
<



<
|












|








|







32
33
34
35
36
37
38
39
40
41
42
43
44



45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
do_execsql_test 1.1.1 {
  CREATE VIRTUAL TABLE t1 USING fts4;
}
do_execsql_test 1.1.2 "INSERT INTO t1 VALUES('[string repeat {a } 20000]')"
do_execsql_test 1.1.3 "INSERT INTO t1 VALUES('[string repeat {z } 20000]')"
do_execsql_test 1.1.4 {
  INSERT INTO t1 VALUES('a b c d e f a x y');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1 VALUES('');
  INSERT INTO t1(t1) VALUES('optimize');



}
do_execsql_test 1.1.4 {
  SELECT count(*) FROM t1_segments WHERE length(block)>10000;

  UPDATE t1_segments SET block = zeroblob(length(block)) WHERE length(block)>10000;
} {2}

do_execsql_test 1.2.1 {
  SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} {{a b c d e f a x y}}

do_execsql_test 1.2.2 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} [list                              \
   {a b c d [e] [f] [a] x y}         \
   {0 1 8 1 0 0 10 1 0 2 12 1}       \
   [list 3 1   1 1 1   1 8 8   1 8 8   8 5001 9]
]

do_execsql_test 1.2.3 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/3 a)';
} [list                                 \
   {[a] b c d [e] [f] [a] x y}          \
   {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
   [list 3 1   1 1 1   1 8 8   2 8 8   8 5001 9]
]

do_execsql_test 1.3.1 { DROP TABLE t1 }

#-----------------------------------------------------------------------------
# Test cases fts3defer2-2.* focus specifically on the matchinfo function.
# 
100
101
102
103
104
105
106






107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

do_execsql_test 2.3.1 {
  CREATE VIRTUAL TABLE t3 USING fts4;
  INSERT INTO t3 VALUES('a b c d e f');
  INSERT INTO t3 VALUES('x b c d e f');
  INSERT INTO t3 VALUES('d e f a b c');
  INSERT INTO t3 VALUES('b c d e f');






}
do_execsql_test 2.3.2 "
  INSERT INTO t3 VALUES('f e d c b [string repeat {a } 10000]')
"
foreach {tn sql} {
  1 {}
  2 { INSERT INTO t3(t3) VALUES('optimize') }
  3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  execsql $sql
  do_execsql_test 2.4.$tn {
    SELECT docid, mit(matchinfo(t3)) FROM t3 WHERE t3 MATCH '"a b c"';
  } {1 {1 1 1 4 4 5 2006 6} 3 {1 1 1 4 4 5 2006 6}}
}


finish_test








>
>
>
>
>
>














|





101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

do_execsql_test 2.3.1 {
  CREATE VIRTUAL TABLE t3 USING fts4;
  INSERT INTO t3 VALUES('a b c d e f');
  INSERT INTO t3 VALUES('x b c d e f');
  INSERT INTO t3 VALUES('d e f a b c');
  INSERT INTO t3 VALUES('b c d e f');
  INSERT INTO t3 VALUES('');
  INSERT INTO t3 VALUES('');
  INSERT INTO t3 VALUES('');
  INSERT INTO t3 VALUES('');
  INSERT INTO t3 VALUES('');
  INSERT INTO t3 VALUES('');
}
do_execsql_test 2.3.2 "
  INSERT INTO t3 VALUES('f e d c b [string repeat {a } 10000]')
"
foreach {tn sql} {
  1 {}
  2 { INSERT INTO t3(t3) VALUES('optimize') }
  3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  execsql $sql
  do_execsql_test 2.4.$tn {
    SELECT docid, mit(matchinfo(t3)) FROM t3 WHERE t3 MATCH '"a b c"';
  } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
}


finish_test