OLD | NEW |
| (Empty) |
1 From 106d71238a58d4dfbeb8cf1cba45a1c4e6f583e8 Mon Sep 17 00:00:00 2001 | |
2 From: Chris Evans <cevans@chromium.org> | |
3 Date: Wed, 30 Sep 2009 23:10:34 +0000 | |
4 Subject: [PATCH 23/23] [fts2] Fix numerous out-of-bounds bugs reading corrupt | |
5 database. | |
6 | |
7 Fix numerous bugs in fts2 where a corrupt fts2 database could cause | |
8 out-of-bounds reads and writes. | |
9 | |
10 Original review URL is more descriptive: | |
11 http://codereview.chromium.org/216026 | |
12 --- | |
13 third_party/sqlite/src/ext/fts2/fts2.c | 751 ++++++++++++++++++++++----------- | |
14 1 file changed, 514 insertions(+), 237 deletions(-) | |
15 | |
16 diff --git a/third_party/sqlite/src/ext/fts2/fts2.c b/third_party/sqlite/src/ext
/fts2/fts2.c | |
17 index d5587b3..36d14ff 100644 | |
18 --- a/third_party/sqlite/src/ext/fts2/fts2.c | |
19 +++ b/third_party/sqlite/src/ext/fts2/fts2.c | |
20 @@ -447,30 +447,41 @@ static int putVarint(char *p, sqlite_int64 v){ | |
21 /* Read a 64-bit variable-length integer from memory starting at p[0]. | |
22 * Return the number of bytes read, or 0 on error. | |
23 * The value is stored in *v. */ | |
24 -static int getVarint(const char *p, sqlite_int64 *v){ | |
25 +static int getVarintSafe(const char *p, sqlite_int64 *v, int max){ | |
26 const unsigned char *q = (const unsigned char *) p; | |
27 sqlite_uint64 x = 0, y = 1; | |
28 - while( (*q & 0x80) == 0x80 ){ | |
29 + if( max>VARINT_MAX ) max = VARINT_MAX; | |
30 + while( max && (*q & 0x80) == 0x80 ){ | |
31 + max--; | |
32 x += y * (*q++ & 0x7f); | |
33 y <<= 7; | |
34 - if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ | |
35 - assert( 0 ); | |
36 - return 0; | |
37 - } | |
38 + } | |
39 + if ( !max ){ | |
40 + assert( 0 ); | |
41 + return 0; /* tried to read too much; bad data */ | |
42 } | |
43 x += y * (*q++); | |
44 *v = (sqlite_int64) x; | |
45 return (int) (q - (unsigned char *)p); | |
46 } | |
47 | |
48 -static int getVarint32(const char *p, int *pi){ | |
49 +static int getVarint(const char *p, sqlite_int64 *v){ | |
50 + return getVarintSafe(p, v, VARINT_MAX); | |
51 +} | |
52 + | |
53 +static int getVarint32Safe(const char *p, int *pi, int max){ | |
54 sqlite_int64 i; | |
55 - int ret = getVarint(p, &i); | |
56 + int ret = getVarintSafe(p, &i, max); | |
57 + if( !ret ) return ret; | |
58 *pi = (int) i; | |
59 assert( *pi==i ); | |
60 return ret; | |
61 } | |
62 | |
63 +static int getVarint32(const char* p, int *pi){ | |
64 + return getVarint32Safe(p, pi, VARINT_MAX); | |
65 +} | |
66 + | |
67 /*******************************************************************/ | |
68 /* DataBuffer is used to collect data into a buffer in piecemeal | |
69 ** fashion. It implements the usual distinction between amount of | |
70 @@ -639,7 +650,7 @@ typedef struct DLReader { | |
71 | |
72 static int dlrAtEnd(DLReader *pReader){ | |
73 assert( pReader->nData>=0 ); | |
74 - return pReader->nData==0; | |
75 + return pReader->nData<=0; | |
76 } | |
77 static sqlite_int64 dlrDocid(DLReader *pReader){ | |
78 assert( !dlrAtEnd(pReader) ); | |
79 @@ -663,7 +674,8 @@ static int dlrAllDataBytes(DLReader *pReader){ | |
80 */ | |
81 static const char *dlrPosData(DLReader *pReader){ | |
82 sqlite_int64 iDummy; | |
83 - int n = getVarint(pReader->pData, &iDummy); | |
84 + int n = getVarintSafe(pReader->pData, &iDummy, pReader->nElement); | |
85 + if( !n ) return NULL; | |
86 assert( !dlrAtEnd(pReader) ); | |
87 return pReader->pData+n; | |
88 } | |
89 @@ -673,7 +685,7 @@ static int dlrPosDataLen(DLReader *pReader){ | |
90 assert( !dlrAtEnd(pReader) ); | |
91 return pReader->nElement-n; | |
92 } | |
93 -static void dlrStep(DLReader *pReader){ | |
94 +static int dlrStep(DLReader *pReader){ | |
95 assert( !dlrAtEnd(pReader) ); | |
96 | |
97 /* Skip past current doclist element. */ | |
98 @@ -682,32 +694,48 @@ static void dlrStep(DLReader *pReader){ | |
99 pReader->nData -= pReader->nElement; | |
100 | |
101 /* If there is more data, read the next doclist element. */ | |
102 - if( pReader->nData!=0 ){ | |
103 + if( pReader->nData>0 ){ | |
104 sqlite_int64 iDocidDelta; | |
105 - int iDummy, n = getVarint(pReader->pData, &iDocidDelta); | |
106 + int nTotal = 0; | |
107 + int iDummy, n = getVarintSafe(pReader->pData, &iDocidDelta, pReader->nData)
; | |
108 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
109 + nTotal += n; | |
110 pReader->iDocid += iDocidDelta; | |
111 if( pReader->iType>=DL_POSITIONS ){ | |
112 - assert( n<pReader->nData ); | |
113 while( 1 ){ | |
114 - n += getVarint32(pReader->pData+n, &iDummy); | |
115 - assert( n<=pReader->nData ); | |
116 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
117 + pReader->nData-nTotal); | |
118 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
119 + nTotal += n; | |
120 if( iDummy==POS_END ) break; | |
121 if( iDummy==POS_COLUMN ){ | |
122 - n += getVarint32(pReader->pData+n, &iDummy); | |
123 - assert( n<pReader->nData ); | |
124 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
125 + pReader->nData-nTotal); | |
126 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
127 + nTotal += n; | |
128 }else if( pReader->iType==DL_POSITIONS_OFFSETS ){ | |
129 - n += getVarint32(pReader->pData+n, &iDummy); | |
130 - n += getVarint32(pReader->pData+n, &iDummy); | |
131 - assert( n<pReader->nData ); | |
132 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
133 + pReader->nData-nTotal); | |
134 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
135 + nTotal += n; | |
136 + n = getVarint32Safe(pReader->pData+nTotal, &iDummy, | |
137 + pReader->nData-nTotal); | |
138 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
139 + nTotal += n; | |
140 } | |
141 } | |
142 } | |
143 - pReader->nElement = n; | |
144 + pReader->nElement = nTotal; | |
145 assert( pReader->nElement<=pReader->nData ); | |
146 } | |
147 + return SQLITE_OK; | |
148 } | |
149 -static void dlrInit(DLReader *pReader, DocListType iType, | |
150 - const char *pData, int nData){ | |
151 +static void dlrDestroy(DLReader *pReader){ | |
152 + SCRAMBLE(pReader); | |
153 +} | |
154 +static int dlrInit(DLReader *pReader, DocListType iType, | |
155 + const char *pData, int nData){ | |
156 + int rc; | |
157 assert( pData!=NULL && nData!=0 ); | |
158 pReader->iType = iType; | |
159 pReader->pData = pData; | |
160 @@ -716,10 +744,9 @@ static void dlrInit(DLReader *pReader, DocListType iType, | |
161 pReader->iDocid = 0; | |
162 | |
163 /* Load the first element's data. There must be a first element. */ | |
164 - dlrStep(pReader); | |
165 -} | |
166 -static void dlrDestroy(DLReader *pReader){ | |
167 - SCRAMBLE(pReader); | |
168 + rc = dlrStep(pReader); | |
169 + if( rc!=SQLITE_OK ) dlrDestroy(pReader); | |
170 + return rc; | |
171 } | |
172 | |
173 #ifndef NDEBUG | |
174 @@ -806,9 +833,9 @@ static void dlwDestroy(DLWriter *pWriter){ | |
175 /* TODO(shess) This has become just a helper for docListMerge. | |
176 ** Consider a refactor to make this cleaner. | |
177 */ | |
178 -static void dlwAppend(DLWriter *pWriter, | |
179 - const char *pData, int nData, | |
180 - sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | |
181 +static int dlwAppend(DLWriter *pWriter, | |
182 + const char *pData, int nData, | |
183 + sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ | |
184 sqlite_int64 iDocid = 0; | |
185 char c[VARINT_MAX]; | |
186 int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ | |
187 @@ -817,7 +844,8 @@ static void dlwAppend(DLWriter *pWriter, | |
188 #endif | |
189 | |
190 /* Recode the initial docid as delta from iPrevDocid. */ | |
191 - nFirstOld = getVarint(pData, &iDocid); | |
192 + nFirstOld = getVarintSafe(pData, &iDocid, nData); | |
193 + if( !nFirstOld ) return SQLITE_CORRUPT_BKPT; | |
194 assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); | |
195 nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); | |
196 | |
197 @@ -838,10 +866,11 @@ static void dlwAppend(DLWriter *pWriter, | |
198 dataBufferAppend(pWriter->b, c, nFirstNew); | |
199 } | |
200 pWriter->iPrevDocid = iLastDocid; | |
201 + return SQLITE_OK; | |
202 } | |
203 -static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ | |
204 - dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | |
205 - dlrDocid(pReader), dlrDocid(pReader)); | |
206 +static int dlwCopy(DLWriter *pWriter, DLReader *pReader){ | |
207 + return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), | |
208 + dlrDocid(pReader), dlrDocid(pReader)); | |
209 } | |
210 static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ | |
211 char c[VARINT_MAX]; | |
212 @@ -902,45 +931,63 @@ static int plrEndOffset(PLReader *pReader){ | |
213 assert( !plrAtEnd(pReader) ); | |
214 return pReader->iEndOffset; | |
215 } | |
216 -static void plrStep(PLReader *pReader){ | |
217 - int i, n; | |
218 +static int plrStep(PLReader *pReader){ | |
219 + int i, n, nTotal = 0; | |
220 | |
221 assert( !plrAtEnd(pReader) ); | |
222 | |
223 - if( pReader->nData==0 ){ | |
224 + if( pReader->nData<=0 ){ | |
225 pReader->pData = NULL; | |
226 - return; | |
227 + return SQLITE_OK; | |
228 } | |
229 | |
230 - n = getVarint32(pReader->pData, &i); | |
231 + n = getVarint32Safe(pReader->pData, &i, pReader->nData); | |
232 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
233 + nTotal += n; | |
234 if( i==POS_COLUMN ){ | |
235 - n += getVarint32(pReader->pData+n, &pReader->iColumn); | |
236 + n = getVarint32Safe(pReader->pData+nTotal, &pReader->iColumn, | |
237 + pReader->nData-nTotal); | |
238 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
239 + nTotal += n; | |
240 pReader->iPosition = 0; | |
241 pReader->iStartOffset = 0; | |
242 - n += getVarint32(pReader->pData+n, &i); | |
243 + n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
244 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
245 + nTotal += n; | |
246 } | |
247 /* Should never see adjacent column changes. */ | |
248 assert( i!=POS_COLUMN ); | |
249 | |
250 if( i==POS_END ){ | |
251 + assert( nTotal<=pReader->nData ); | |
252 pReader->nData = 0; | |
253 pReader->pData = NULL; | |
254 - return; | |
255 + return SQLITE_OK; | |
256 } | |
257 | |
258 pReader->iPosition += i-POS_BASE; | |
259 if( pReader->iType==DL_POSITIONS_OFFSETS ){ | |
260 - n += getVarint32(pReader->pData+n, &i); | |
261 + n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
262 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
263 + nTotal += n; | |
264 pReader->iStartOffset += i; | |
265 - n += getVarint32(pReader->pData+n, &i); | |
266 + n = getVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal); | |
267 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
268 + nTotal += n; | |
269 pReader->iEndOffset = pReader->iStartOffset+i; | |
270 } | |
271 - assert( n<=pReader->nData ); | |
272 - pReader->pData += n; | |
273 - pReader->nData -= n; | |
274 + assert( nTotal<=pReader->nData ); | |
275 + pReader->pData += nTotal; | |
276 + pReader->nData -= nTotal; | |
277 + return SQLITE_OK; | |
278 } | |
279 | |
280 -static void plrInit(PLReader *pReader, DLReader *pDLReader){ | |
281 +static void plrDestroy(PLReader *pReader){ | |
282 + SCRAMBLE(pReader); | |
283 +} | |
284 + | |
285 +static int plrInit(PLReader *pReader, DLReader *pDLReader){ | |
286 + int rc; | |
287 pReader->pData = dlrPosData(pDLReader); | |
288 pReader->nData = dlrPosDataLen(pDLReader); | |
289 pReader->iType = pDLReader->iType; | |
290 @@ -948,10 +995,9 @@ static void plrInit(PLReader *pReader, DLReader *pDLReader)
{ | |
291 pReader->iPosition = 0; | |
292 pReader->iStartOffset = 0; | |
293 pReader->iEndOffset = 0; | |
294 - plrStep(pReader); | |
295 -} | |
296 -static void plrDestroy(PLReader *pReader){ | |
297 - SCRAMBLE(pReader); | |
298 + rc = plrStep(pReader); | |
299 + if( rc!=SQLITE_OK ) plrDestroy(pReader); | |
300 + return rc; | |
301 } | |
302 | |
303 /*******************************************************************/ | |
304 @@ -1137,14 +1183,16 @@ static void dlcDelete(DLCollector *pCollector){ | |
305 ** deletion will be trimmed, and will thus not effect a deletion | |
306 ** during the merge. | |
307 */ | |
308 -static void docListTrim(DocListType iType, const char *pData, int nData, | |
309 - int iColumn, DocListType iOutType, DataBuffer *out){ | |
310 +static int docListTrim(DocListType iType, const char *pData, int nData, | |
311 + int iColumn, DocListType iOutType, DataBuffer *out){ | |
312 DLReader dlReader; | |
313 DLWriter dlWriter; | |
314 + int rc; | |
315 | |
316 assert( iOutType<=iType ); | |
317 | |
318 - dlrInit(&dlReader, iType, pData, nData); | |
319 + rc = dlrInit(&dlReader, iType, pData, nData); | |
320 + if( rc!=SQLITE_OK ) return rc; | |
321 dlwInit(&dlWriter, iOutType, out); | |
322 | |
323 while( !dlrAtEnd(&dlReader) ){ | |
324 @@ -1152,7 +1200,8 @@ static void docListTrim(DocListType iType, const char *pDa
ta, int nData, | |
325 PLWriter plWriter; | |
326 int match = 0; | |
327 | |
328 - plrInit(&plReader, &dlReader); | |
329 + rc = plrInit(&plReader, &dlReader); | |
330 + if( rc!=SQLITE_OK ) break; | |
331 | |
332 while( !plrAtEnd(&plReader) ){ | |
333 if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ | |
334 @@ -1163,7 +1212,11 @@ static void docListTrim(DocListType iType, const char *pD
ata, int nData, | |
335 plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), | |
336 plrStartOffset(&plReader), plrEndOffset(&plReader)); | |
337 } | |
338 - plrStep(&plReader); | |
339 + rc = plrStep(&plReader); | |
340 + if( rc!=SQLITE_OK ){ | |
341 + plrDestroy(&plReader); | |
342 + goto err; | |
343 + } | |
344 } | |
345 if( match ){ | |
346 plwTerminate(&plWriter); | |
347 @@ -1171,10 +1224,13 @@ static void docListTrim(DocListType iType, const char *p
Data, int nData, | |
348 } | |
349 | |
350 plrDestroy(&plReader); | |
351 - dlrStep(&dlReader); | |
352 + rc = dlrStep(&dlReader); | |
353 + if( rc!=SQLITE_OK ) break; | |
354 } | |
355 +err: | |
356 dlwDestroy(&dlWriter); | |
357 dlrDestroy(&dlReader); | |
358 + return rc; | |
359 } | |
360 | |
361 /* Used by docListMerge() to keep doclists in the ascending order by | |
362 @@ -1231,19 +1287,20 @@ static void orderedDLReaderReorder(OrderedDLReader *p, i
nt n){ | |
363 /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably | |
364 ** be fixed. | |
365 */ | |
366 -static void docListMerge(DataBuffer *out, | |
367 - DLReader *pReaders, int nReaders){ | |
368 +static int docListMerge(DataBuffer *out, | |
369 + DLReader *pReaders, int nReaders){ | |
370 OrderedDLReader readers[MERGE_COUNT]; | |
371 DLWriter writer; | |
372 int i, n; | |
373 const char *pStart = 0; | |
374 int nStart = 0; | |
375 sqlite_int64 iFirstDocid = 0, iLastDocid = 0; | |
376 + int rc = SQLITE_OK; | |
377 | |
378 assert( nReaders>0 ); | |
379 if( nReaders==1 ){ | |
380 dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); | |
381 - return; | |
382 + return SQLITE_OK; | |
383 } | |
384 | |
385 assert( nReaders<=MERGE_COUNT ); | |
386 @@ -1276,20 +1333,23 @@ static void docListMerge(DataBuffer *out, | |
387 nStart += dlrDocDataBytes(readers[0].pReader); | |
388 }else{ | |
389 if( pStart!=0 ){ | |
390 - dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
391 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
392 + if( rc!=SQLITE_OK ) goto err; | |
393 } | |
394 pStart = dlrDocData(readers[0].pReader); | |
395 nStart = dlrDocDataBytes(readers[0].pReader); | |
396 iFirstDocid = iDocid; | |
397 } | |
398 iLastDocid = iDocid; | |
399 - dlrStep(readers[0].pReader); | |
400 + rc = dlrStep(readers[0].pReader); | |
401 + if( rc!=SQLITE_OK ) goto err; | |
402 | |
403 /* Drop all of the older elements with the same docid. */ | |
404 for(i=1; i<nReaders && | |
405 !dlrAtEnd(readers[i].pReader) && | |
406 dlrDocid(readers[i].pReader)==iDocid; i++){ | |
407 - dlrStep(readers[i].pReader); | |
408 + rc = dlrStep(readers[i].pReader); | |
409 + if( rc!=SQLITE_OK ) goto err; | |
410 } | |
411 | |
412 /* Get the readers back into order. */ | |
413 @@ -1299,8 +1359,11 @@ static void docListMerge(DataBuffer *out, | |
414 } | |
415 | |
416 /* Copy over any remaining elements. */ | |
417 - if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
418 + if( nStart>0 ) | |
419 + rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); | |
420 +err: | |
421 dlwDestroy(&writer); | |
422 + return rc; | |
423 } | |
424 | |
425 /* Helper function for posListUnion(). Compares the current position | |
426 @@ -1336,30 +1399,40 @@ static int posListCmp(PLReader *pLeft, PLReader *pRight)
{ | |
427 ** work with any doclist type, though both inputs and the output | |
428 ** should be the same type. | |
429 */ | |
430 -static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | |
431 +static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ | |
432 PLReader left, right; | |
433 PLWriter writer; | |
434 + int rc; | |
435 | |
436 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | |
437 assert( pLeft->iType==pRight->iType ); | |
438 assert( pLeft->iType==pOut->iType ); | |
439 | |
440 - plrInit(&left, pLeft); | |
441 - plrInit(&right, pRight); | |
442 + rc = plrInit(&left, pLeft); | |
443 + if( rc != SQLITE_OK ) return rc; | |
444 + rc = plrInit(&right, pRight); | |
445 + if( rc != SQLITE_OK ){ | |
446 + plrDestroy(&left); | |
447 + return rc; | |
448 + } | |
449 plwInit(&writer, pOut, dlrDocid(pLeft)); | |
450 | |
451 while( !plrAtEnd(&left) || !plrAtEnd(&right) ){ | |
452 int c = posListCmp(&left, &right); | |
453 if( c<0 ){ | |
454 plwCopy(&writer, &left); | |
455 - plrStep(&left); | |
456 + rc = plrStep(&left); | |
457 + if( rc != SQLITE_OK ) break; | |
458 }else if( c>0 ){ | |
459 plwCopy(&writer, &right); | |
460 - plrStep(&right); | |
461 + rc = plrStep(&right); | |
462 + if( rc != SQLITE_OK ) break; | |
463 }else{ | |
464 plwCopy(&writer, &left); | |
465 - plrStep(&left); | |
466 - plrStep(&right); | |
467 + rc = plrStep(&left); | |
468 + if( rc != SQLITE_OK ) break; | |
469 + rc = plrStep(&right); | |
470 + if( rc != SQLITE_OK ) break; | |
471 } | |
472 } | |
473 | |
474 @@ -1367,56 +1440,75 @@ static void posListUnion(DLReader *pLeft, DLReader *pRig
ht, DLWriter *pOut){ | |
475 plwDestroy(&writer); | |
476 plrDestroy(&left); | |
477 plrDestroy(&right); | |
478 + return rc; | |
479 } | |
480 | |
481 /* Write the union of doclists in pLeft and pRight to pOut. For | |
482 ** docids in common between the inputs, the union of the position | |
483 ** lists is written. Inputs and outputs are always type DL_DEFAULT. | |
484 */ | |
485 -static void docListUnion( | |
486 +static int docListUnion( | |
487 const char *pLeft, int nLeft, | |
488 const char *pRight, int nRight, | |
489 DataBuffer *pOut /* Write the combined doclist here */ | |
490 ){ | |
491 DLReader left, right; | |
492 DLWriter writer; | |
493 + int rc; | |
494 | |
495 if( nLeft==0 ){ | |
496 if( nRight!=0) dataBufferAppend(pOut, pRight, nRight); | |
497 - return; | |
498 + return SQLITE_OK; | |
499 } | |
500 if( nRight==0 ){ | |
501 dataBufferAppend(pOut, pLeft, nLeft); | |
502 - return; | |
503 + return SQLITE_OK; | |
504 } | |
505 | |
506 - dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | |
507 - dlrInit(&right, DL_DEFAULT, pRight, nRight); | |
508 + rc = dlrInit(&left, DL_DEFAULT, pLeft, nLeft); | |
509 + if( rc!=SQLITE_OK ) return rc; | |
510 + rc = dlrInit(&right, DL_DEFAULT, pRight, nRight); | |
511 + if( rc!=SQLITE_OK ){ | |
512 + dlrDestroy(&left); | |
513 + return rc; | |
514 + } | |
515 dlwInit(&writer, DL_DEFAULT, pOut); | |
516 | |
517 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | |
518 if( dlrAtEnd(&right) ){ | |
519 - dlwCopy(&writer, &left); | |
520 - dlrStep(&left); | |
521 + rc = dlwCopy(&writer, &left); | |
522 + if( rc!=SQLITE_OK ) break; | |
523 + rc = dlrStep(&left); | |
524 + if( rc!=SQLITE_OK ) break; | |
525 }else if( dlrAtEnd(&left) ){ | |
526 - dlwCopy(&writer, &right); | |
527 - dlrStep(&right); | |
528 + rc = dlwCopy(&writer, &right); | |
529 + if( rc!=SQLITE_OK ) break; | |
530 + rc = dlrStep(&right); | |
531 + if( rc!=SQLITE_OK ) break; | |
532 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | |
533 - dlwCopy(&writer, &left); | |
534 - dlrStep(&left); | |
535 + rc = dlwCopy(&writer, &left); | |
536 + if( rc!=SQLITE_OK ) break; | |
537 + rc = dlrStep(&left); | |
538 + if( rc!=SQLITE_OK ) break; | |
539 }else if( dlrDocid(&left)>dlrDocid(&right) ){ | |
540 - dlwCopy(&writer, &right); | |
541 - dlrStep(&right); | |
542 + rc = dlwCopy(&writer, &right); | |
543 + if( rc!=SQLITE_OK ) break; | |
544 + rc = dlrStep(&right); | |
545 + if( rc!=SQLITE_OK ) break; | |
546 }else{ | |
547 - posListUnion(&left, &right, &writer); | |
548 - dlrStep(&left); | |
549 - dlrStep(&right); | |
550 + rc = posListUnion(&left, &right, &writer); | |
551 + if( rc!=SQLITE_OK ) break; | |
552 + rc = dlrStep(&left); | |
553 + if( rc!=SQLITE_OK ) break; | |
554 + rc = dlrStep(&right); | |
555 + if( rc!=SQLITE_OK ) break; | |
556 } | |
557 } | |
558 | |
559 dlrDestroy(&left); | |
560 dlrDestroy(&right); | |
561 dlwDestroy(&writer); | |
562 + return rc; | |
563 } | |
564 | |
565 /* pLeft and pRight are DLReaders positioned to the same docid. | |
566 @@ -1431,35 +1523,47 @@ static void docListUnion( | |
567 ** include the positions from pRight that are one more than a | |
568 ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. | |
569 */ | |
570 -static void posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | |
571 - DLWriter *pOut){ | |
572 +static int posListPhraseMerge(DLReader *pLeft, DLReader *pRight, | |
573 + DLWriter *pOut){ | |
574 PLReader left, right; | |
575 PLWriter writer; | |
576 int match = 0; | |
577 + int rc; | |
578 | |
579 assert( dlrDocid(pLeft)==dlrDocid(pRight) ); | |
580 assert( pOut->iType!=DL_POSITIONS_OFFSETS ); | |
581 | |
582 - plrInit(&left, pLeft); | |
583 - plrInit(&right, pRight); | |
584 + rc = plrInit(&left, pLeft); | |
585 + if( rc!=SQLITE_OK ) return rc; | |
586 + rc = plrInit(&right, pRight); | |
587 + if( rc!=SQLITE_OK ){ | |
588 + plrDestroy(&left); | |
589 + return rc; | |
590 + } | |
591 | |
592 while( !plrAtEnd(&left) && !plrAtEnd(&right) ){ | |
593 if( plrColumn(&left)<plrColumn(&right) ){ | |
594 - plrStep(&left); | |
595 + rc = plrStep(&left); | |
596 + if( rc!=SQLITE_OK ) break; | |
597 }else if( plrColumn(&left)>plrColumn(&right) ){ | |
598 - plrStep(&right); | |
599 + rc = plrStep(&right); | |
600 + if( rc!=SQLITE_OK ) break; | |
601 }else if( plrPosition(&left)+1<plrPosition(&right) ){ | |
602 - plrStep(&left); | |
603 + rc = plrStep(&left); | |
604 + if( rc!=SQLITE_OK ) break; | |
605 }else if( plrPosition(&left)+1>plrPosition(&right) ){ | |
606 - plrStep(&right); | |
607 + rc = plrStep(&right); | |
608 + if( rc!=SQLITE_OK ) break; | |
609 }else{ | |
610 if( !match ){ | |
611 plwInit(&writer, pOut, dlrDocid(pLeft)); | |
612 match = 1; | |
613 } | |
614 plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); | |
615 - plrStep(&left); | |
616 - plrStep(&right); | |
617 + rc = plrStep(&left); | |
618 + if( rc!=SQLITE_OK ) break; | |
619 + rc = plrStep(&right); | |
620 + if( rc!=SQLITE_OK ) break; | |
621 } | |
622 } | |
623 | |
624 @@ -1470,6 +1574,7 @@ static void posListPhraseMerge(DLReader *pLeft, DLReader *
pRight, | |
625 | |
626 plrDestroy(&left); | |
627 plrDestroy(&right); | |
628 + return rc; | |
629 } | |
630 | |
631 /* We have two doclists with positions: pLeft and pRight. | |
632 @@ -1481,7 +1586,7 @@ static void posListPhraseMerge(DLReader *pLeft, DLReader *
pRight, | |
633 ** iType controls the type of data written to pOut. If iType is | |
634 ** DL_POSITIONS, the positions are those from pRight. | |
635 */ | |
636 -static void docListPhraseMerge( | |
637 +static int docListPhraseMerge( | |
638 const char *pLeft, int nLeft, | |
639 const char *pRight, int nRight, | |
640 DocListType iType, | |
641 @@ -1489,152 +1594,198 @@ static void docListPhraseMerge( | |
642 ){ | |
643 DLReader left, right; | |
644 DLWriter writer; | |
645 + int rc; | |
646 | |
647 - if( nLeft==0 || nRight==0 ) return; | |
648 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | |
649 | |
650 assert( iType!=DL_POSITIONS_OFFSETS ); | |
651 | |
652 - dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | |
653 - dlrInit(&right, DL_POSITIONS, pRight, nRight); | |
654 + rc = dlrInit(&left, DL_POSITIONS, pLeft, nLeft); | |
655 + if( rc!=SQLITE_OK ) return rc; | |
656 + rc = dlrInit(&right, DL_POSITIONS, pRight, nRight); | |
657 + if( rc!=SQLITE_OK ){ | |
658 + dlrDestroy(&left); | |
659 + return rc; | |
660 + } | |
661 dlwInit(&writer, iType, pOut); | |
662 | |
663 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | |
664 if( dlrDocid(&left)<dlrDocid(&right) ){ | |
665 - dlrStep(&left); | |
666 + rc = dlrStep(&left); | |
667 + if( rc!=SQLITE_OK ) break; | |
668 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
669 - dlrStep(&right); | |
670 + rc = dlrStep(&right); | |
671 + if( rc!=SQLITE_OK ) break; | |
672 }else{ | |
673 - posListPhraseMerge(&left, &right, &writer); | |
674 - dlrStep(&left); | |
675 - dlrStep(&right); | |
676 + rc = posListPhraseMerge(&left, &right, &writer); | |
677 + if( rc!=SQLITE_OK ) break; | |
678 + rc = dlrStep(&left); | |
679 + if( rc!=SQLITE_OK ) break; | |
680 + rc = dlrStep(&right); | |
681 + if( rc!=SQLITE_OK ) break; | |
682 } | |
683 } | |
684 | |
685 dlrDestroy(&left); | |
686 dlrDestroy(&right); | |
687 dlwDestroy(&writer); | |
688 + return rc; | |
689 } | |
690 | |
691 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
692 ** Write the intersection of these two doclists into pOut as a | |
693 ** DL_DOCIDS doclist. | |
694 */ | |
695 -static void docListAndMerge( | |
696 +static int docListAndMerge( | |
697 const char *pLeft, int nLeft, | |
698 const char *pRight, int nRight, | |
699 DataBuffer *pOut /* Write the combined doclist here */ | |
700 ){ | |
701 DLReader left, right; | |
702 DLWriter writer; | |
703 + int rc; | |
704 | |
705 - if( nLeft==0 || nRight==0 ) return; | |
706 + if( nLeft==0 || nRight==0 ) return SQLITE_OK; | |
707 | |
708 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
709 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
710 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
711 + if( rc!=SQLITE_OK ) return rc; | |
712 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
713 + if( rc!=SQLITE_OK ){ | |
714 + dlrDestroy(&left); | |
715 + return rc; | |
716 + } | |
717 dlwInit(&writer, DL_DOCIDS, pOut); | |
718 | |
719 while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ | |
720 if( dlrDocid(&left)<dlrDocid(&right) ){ | |
721 - dlrStep(&left); | |
722 + rc = dlrStep(&left); | |
723 + if( rc!=SQLITE_OK ) break; | |
724 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
725 - dlrStep(&right); | |
726 + rc = dlrStep(&right); | |
727 + if( rc!=SQLITE_OK ) break; | |
728 }else{ | |
729 dlwAdd(&writer, dlrDocid(&left)); | |
730 - dlrStep(&left); | |
731 - dlrStep(&right); | |
732 + rc = dlrStep(&left); | |
733 + if( rc!=SQLITE_OK ) break; | |
734 + rc = dlrStep(&right); | |
735 + if( rc!=SQLITE_OK ) break; | |
736 } | |
737 } | |
738 | |
739 dlrDestroy(&left); | |
740 dlrDestroy(&right); | |
741 dlwDestroy(&writer); | |
742 + return rc; | |
743 } | |
744 | |
745 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
746 ** Write the union of these two doclists into pOut as a | |
747 ** DL_DOCIDS doclist. | |
748 */ | |
749 -static void docListOrMerge( | |
750 +static int docListOrMerge( | |
751 const char *pLeft, int nLeft, | |
752 const char *pRight, int nRight, | |
753 DataBuffer *pOut /* Write the combined doclist here */ | |
754 ){ | |
755 DLReader left, right; | |
756 DLWriter writer; | |
757 + int rc; | |
758 | |
759 if( nLeft==0 ){ | |
760 if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight); | |
761 - return; | |
762 + return SQLITE_OK; | |
763 } | |
764 if( nRight==0 ){ | |
765 dataBufferAppend(pOut, pLeft, nLeft); | |
766 - return; | |
767 + return SQLITE_OK; | |
768 } | |
769 | |
770 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
771 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
772 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
773 + if( rc!=SQLITE_OK ) return rc; | |
774 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
775 + if( rc!=SQLITE_OK ){ | |
776 + dlrDestroy(&left); | |
777 + return rc; | |
778 + } | |
779 dlwInit(&writer, DL_DOCIDS, pOut); | |
780 | |
781 while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ | |
782 if( dlrAtEnd(&right) ){ | |
783 dlwAdd(&writer, dlrDocid(&left)); | |
784 - dlrStep(&left); | |
785 + rc = dlrStep(&left); | |
786 + if( rc!=SQLITE_OK ) break; | |
787 }else if( dlrAtEnd(&left) ){ | |
788 dlwAdd(&writer, dlrDocid(&right)); | |
789 - dlrStep(&right); | |
790 + rc = dlrStep(&right); | |
791 + if( rc!=SQLITE_OK ) break; | |
792 }else if( dlrDocid(&left)<dlrDocid(&right) ){ | |
793 dlwAdd(&writer, dlrDocid(&left)); | |
794 - dlrStep(&left); | |
795 + rc = dlrStep(&left); | |
796 + if( rc!=SQLITE_OK ) break; | |
797 }else if( dlrDocid(&right)<dlrDocid(&left) ){ | |
798 dlwAdd(&writer, dlrDocid(&right)); | |
799 - dlrStep(&right); | |
800 + rc = dlrStep(&right); | |
801 + if( rc!=SQLITE_OK ) break; | |
802 }else{ | |
803 dlwAdd(&writer, dlrDocid(&left)); | |
804 - dlrStep(&left); | |
805 - dlrStep(&right); | |
806 + rc = dlrStep(&left); | |
807 + if( rc!=SQLITE_OK ) break; | |
808 + rc = dlrStep(&right); | |
809 + if( rc!=SQLITE_OK ) break; | |
810 } | |
811 } | |
812 | |
813 dlrDestroy(&left); | |
814 dlrDestroy(&right); | |
815 dlwDestroy(&writer); | |
816 + return rc; | |
817 } | |
818 | |
819 /* We have two DL_DOCIDS doclists: pLeft and pRight. | |
820 ** Write into pOut as DL_DOCIDS doclist containing all documents that | |
821 ** occur in pLeft but not in pRight. | |
822 */ | |
823 -static void docListExceptMerge( | |
824 +static int docListExceptMerge( | |
825 const char *pLeft, int nLeft, | |
826 const char *pRight, int nRight, | |
827 DataBuffer *pOut /* Write the combined doclist here */ | |
828 ){ | |
829 DLReader left, right; | |
830 DLWriter writer; | |
831 + int rc; | |
832 | |
833 - if( nLeft==0 ) return; | |
834 + if( nLeft==0 ) return SQLITE_OK; | |
835 if( nRight==0 ){ | |
836 dataBufferAppend(pOut, pLeft, nLeft); | |
837 - return; | |
838 + return SQLITE_OK; | |
839 } | |
840 | |
841 - dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
842 - dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
843 + rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft); | |
844 + if( rc!=SQLITE_OK ) return rc; | |
845 + rc = dlrInit(&right, DL_DOCIDS, pRight, nRight); | |
846 + if( rc!=SQLITE_OK ){ | |
847 + dlrDestroy(&left); | |
848 + return rc; | |
849 + } | |
850 dlwInit(&writer, DL_DOCIDS, pOut); | |
851 | |
852 while( !dlrAtEnd(&left) ){ | |
853 while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){ | |
854 - dlrStep(&right); | |
855 + rc = dlrStep(&right); | |
856 + if( rc!=SQLITE_OK ) goto err; | |
857 } | |
858 if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){ | |
859 dlwAdd(&writer, dlrDocid(&left)); | |
860 } | |
861 - dlrStep(&left); | |
862 + rc = dlrStep(&left); | |
863 + if( rc!=SQLITE_OK ) break; | |
864 } | |
865 | |
866 +err: | |
867 dlrDestroy(&left); | |
868 dlrDestroy(&right); | |
869 dlwDestroy(&writer); | |
870 + return rc; | |
871 } | |
872 | |
873 static char *string_dup_n(const char *s, int n){ | |
874 @@ -3437,7 +3588,8 @@ static int fulltextNext(sqlite3_vtab_cursor *pCursor){ | |
875 return SQLITE_OK; | |
876 } | |
877 rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); | |
878 - dlrStep(&c->reader); | |
879 + if( rc!=SQLITE_OK ) return rc; | |
880 + rc = dlrStep(&c->reader); | |
881 if( rc!=SQLITE_OK ) return rc; | |
882 /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ | |
883 rc = sqlite3_step(c->pStmt); | |
884 @@ -3497,14 +3649,18 @@ static int docListOfTerm( | |
885 return rc; | |
886 } | |
887 dataBufferInit(&new, 0); | |
888 - docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | |
889 - i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); | |
890 + rc = docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, | |
891 + i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new)
; | |
892 dataBufferDestroy(&left); | |
893 dataBufferDestroy(&right); | |
894 + if( rc!=SQLITE_OK ){ | |
895 + dataBufferDestroy(&new); | |
896 + return rc; | |
897 + } | |
898 left = new; | |
899 } | |
900 *pResult = left; | |
901 - return SQLITE_OK; | |
902 + return rc; | |
903 } | |
904 | |
905 /* Add a new term pTerm[0..nTerm-1] to the query *q. | |
906 @@ -3749,18 +3905,30 @@ static int fulltextQuery( | |
907 return rc; | |
908 } | |
909 dataBufferInit(&new, 0); | |
910 - docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | |
911 + rc = docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); | |
912 dataBufferDestroy(&right); | |
913 dataBufferDestroy(&or); | |
914 + if( rc!=SQLITE_OK ){ | |
915 + if( i!=nNot ) dataBufferDestroy(&left); | |
916 + queryClear(pQuery); | |
917 + dataBufferDestroy(&new); | |
918 + return rc; | |
919 + } | |
920 right = new; | |
921 } | |
922 if( i==nNot ){ /* first term processed. */ | |
923 left = right; | |
924 }else{ | |
925 dataBufferInit(&new, 0); | |
926 - docListAndMerge(left.pData, left.nData, right.pData, right.nData, &new); | |
927 + rc = docListAndMerge(left.pData, left.nData, | |
928 + right.pData, right.nData, &new); | |
929 dataBufferDestroy(&right); | |
930 dataBufferDestroy(&left); | |
931 + if( rc!=SQLITE_OK ){ | |
932 + queryClear(pQuery); | |
933 + dataBufferDestroy(&new); | |
934 + return rc; | |
935 + } | |
936 left = new; | |
937 } | |
938 } | |
939 @@ -3780,9 +3948,15 @@ static int fulltextQuery( | |
940 return rc; | |
941 } | |
942 dataBufferInit(&new, 0); | |
943 - docListExceptMerge(left.pData, left.nData, right.pData, right.nData, &new); | |
944 + rc = docListExceptMerge(left.pData, left.nData, | |
945 + right.pData, right.nData, &new); | |
946 dataBufferDestroy(&right); | |
947 dataBufferDestroy(&left); | |
948 + if( rc!=SQLITE_OK ){ | |
949 + queryClear(pQuery); | |
950 + dataBufferDestroy(&new); | |
951 + return rc; | |
952 + } | |
953 left = new; | |
954 } | |
955 | |
956 @@ -3876,7 +4050,8 @@ static int fulltextFilter( | |
957 rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->
q); | |
958 if( rc!=SQLITE_OK ) return rc; | |
959 if( c->result.nData!=0 ){ | |
960 - dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | |
961 + rc = dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); | |
962 + if( rc!=SQLITE_OK ) return rc; | |
963 } | |
964 break; | |
965 } | |
966 @@ -4377,22 +4552,19 @@ static void interiorReaderDestroy(InteriorReader *pReade
r){ | |
967 SCRAMBLE(pReader); | |
968 } | |
969 | |
970 -/* TODO(shess) The assertions are great, but what if we're in NDEBUG | |
971 -** and the blob is empty or otherwise contains suspect data? | |
972 -*/ | |
973 -static void interiorReaderInit(const char *pData, int nData, | |
974 - InteriorReader *pReader){ | |
975 +static int interiorReaderInit(const char *pData, int nData, | |
976 + InteriorReader *pReader){ | |
977 int n, nTerm; | |
978 | |
979 - /* Require at least the leading flag byte */ | |
980 + /* These conditions are checked and met by the callers. */ | |
981 assert( nData>0 ); | |
982 assert( pData[0]!='\0' ); | |
983 | |
984 CLEAR(pReader); | |
985 | |
986 /* Decode the base blockid, and set the cursor to the first term. */ | |
987 - n = getVarint(pData+1, &pReader->iBlockid); | |
988 - assert( 1+n<=nData ); | |
989 + n = getVarintSafe(pData+1, &pReader->iBlockid, nData-1); | |
990 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
991 pReader->pData = pData+1+n; | |
992 pReader->nData = nData-(1+n); | |
993 | |
994 @@ -4403,17 +4575,18 @@ static void interiorReaderInit(const char *pData, int nD
ata, | |
995 if( pReader->nData==0 ){ | |
996 dataBufferInit(&pReader->term, 0); | |
997 }else{ | |
998 - n = getVarint32(pReader->pData, &nTerm); | |
999 + n = getVarint32Safe(pReader->pData, &nTerm, pReader->nData); | |
1000 + if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT; | |
1001 dataBufferInit(&pReader->term, nTerm); | |
1002 dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); | |
1003 - assert( n+nTerm<=pReader->nData ); | |
1004 pReader->pData += n+nTerm; | |
1005 pReader->nData -= n+nTerm; | |
1006 } | |
1007 + return SQLITE_OK; | |
1008 } | |
1009 | |
1010 static int interiorReaderAtEnd(InteriorReader *pReader){ | |
1011 - return pReader->term.nData==0; | |
1012 + return pReader->term.nData<=0; | |
1013 } | |
1014 | |
1015 static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ | |
1016 @@ -4430,7 +4603,7 @@ static const char *interiorReaderTerm(InteriorReader *pRea
der){ | |
1017 } | |
1018 | |
1019 /* Step forward to the next term in the node. */ | |
1020 -static void interiorReaderStep(InteriorReader *pReader){ | |
1021 +static int interiorReaderStep(InteriorReader *pReader){ | |
1022 assert( !interiorReaderAtEnd(pReader) ); | |
1023 | |
1024 /* If the last term has been read, signal eof, else construct the | |
1025 @@ -4441,18 +4614,26 @@ static void interiorReaderStep(InteriorReader *pReader){ | |
1026 }else{ | |
1027 int n, nPrefix, nSuffix; | |
1028 | |
1029 - n = getVarint32(pReader->pData, &nPrefix); | |
1030 - n += getVarint32(pReader->pData+n, &nSuffix); | |
1031 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | |
1032 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
1033 + pReader->nData -= n; | |
1034 + pReader->pData += n; | |
1035 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | |
1036 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
1037 + pReader->nData -= n; | |
1038 + pReader->pData += n; | |
1039 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | |
1040 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | |
1041 | |
1042 /* Truncate the current term and append suffix data. */ | |
1043 pReader->term.nData = nPrefix; | |
1044 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | |
1045 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | |
1046 | |
1047 - assert( n+nSuffix<=pReader->nData ); | |
1048 - pReader->pData += n+nSuffix; | |
1049 - pReader->nData -= n+nSuffix; | |
1050 + pReader->pData += nSuffix; | |
1051 + pReader->nData -= nSuffix; | |
1052 } | |
1053 pReader->iBlockid++; | |
1054 + return SQLITE_OK; | |
1055 } | |
1056 | |
1057 /* Compare the current term to pTerm[nTerm], returning strcmp-style | |
1058 @@ -4824,7 +5005,8 @@ static int leafWriterStepMerge(fulltext_vtab *v, LeafWrite
r *pWriter, | |
1059 n = putVarint(c, nData); | |
1060 dataBufferAppend(&pWriter->data, c, n); | |
1061 | |
1062 - docListMerge(&pWriter->data, pReaders, nReaders); | |
1063 + rc = docListMerge(&pWriter->data, pReaders, nReaders); | |
1064 + if( rc!= SQLITE_OK ) return rc; | |
1065 ASSERT_VALID_DOCLIST(DL_DEFAULT, | |
1066 pWriter->data.pData+iDoclistData+n, | |
1067 pWriter->data.nData-iDoclistData-n, NULL); | |
1068 @@ -4934,7 +5116,8 @@ static int leafWriterStep(fulltext_vtab *v, LeafWriter *pW
riter, | |
1069 int rc; | |
1070 DLReader reader; | |
1071 | |
1072 - dlrInit(&reader, DL_DEFAULT, pData, nData); | |
1073 + rc = dlrInit(&reader, DL_DEFAULT, pData, nData); | |
1074 + if( rc!=SQLITE_OK ) return rc; | |
1075 rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); | |
1076 dlrDestroy(&reader); | |
1077 | |
1078 @@ -4979,38 +5162,40 @@ static int leafReaderDataBytes(LeafReader *pReader){ | |
1079 static const char *leafReaderData(LeafReader *pReader){ | |
1080 int n, nData; | |
1081 assert( pReader->term.nData>0 ); | |
1082 - n = getVarint32(pReader->pData, &nData); | |
1083 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); | |
1084 + if( !n || nData>pReader->nData-n ) return NULL; | |
1085 return pReader->pData+n; | |
1086 } | |
1087 | |
1088 -static void leafReaderInit(const char *pData, int nData, | |
1089 - LeafReader *pReader){ | |
1090 +static int leafReaderInit(const char *pData, int nData, LeafReader *pReader){ | |
1091 int nTerm, n; | |
1092 | |
1093 + /* All callers check this precondition. */ | |
1094 assert( nData>0 ); | |
1095 assert( pData[0]=='\0' ); | |
1096 | |
1097 CLEAR(pReader); | |
1098 | |
1099 /* Read the first term, skipping the header byte. */ | |
1100 - n = getVarint32(pData+1, &nTerm); | |
1101 + n = getVarint32Safe(pData+1, &nTerm, nData-1); | |
1102 + if( !n || nTerm<0 || nTerm>nData-1-n ) return SQLITE_CORRUPT_BKPT; | |
1103 dataBufferInit(&pReader->term, nTerm); | |
1104 dataBufferReplace(&pReader->term, pData+1+n, nTerm); | |
1105 | |
1106 /* Position after the first term. */ | |
1107 - assert( 1+n+nTerm<nData ); | |
1108 pReader->pData = pData+1+n+nTerm; | |
1109 pReader->nData = nData-1-n-nTerm; | |
1110 + return SQLITE_OK; | |
1111 } | |
1112 | |
1113 /* Step the reader forward to the next term. */ | |
1114 -static void leafReaderStep(LeafReader *pReader){ | |
1115 +static int leafReaderStep(LeafReader *pReader){ | |
1116 int n, nData, nPrefix, nSuffix; | |
1117 assert( !leafReaderAtEnd(pReader) ); | |
1118 | |
1119 /* Skip previous entry's data block. */ | |
1120 - n = getVarint32(pReader->pData, &nData); | |
1121 - assert( n+nData<=pReader->nData ); | |
1122 + n = getVarint32Safe(pReader->pData, &nData, pReader->nData); | |
1123 + if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT; | |
1124 pReader->pData += n+nData; | |
1125 pReader->nData -= n+nData; | |
1126 | |
1127 @@ -5018,15 +5203,23 @@ static void leafReaderStep(LeafReader *pReader){ | |
1128 /* Construct the new term using a prefix from the old term plus a | |
1129 ** suffix from the leaf data. | |
1130 */ | |
1131 - n = getVarint32(pReader->pData, &nPrefix); | |
1132 - n += getVarint32(pReader->pData+n, &nSuffix); | |
1133 - assert( n+nSuffix<pReader->nData ); | |
1134 + n = getVarint32Safe(pReader->pData, &nPrefix, pReader->nData); | |
1135 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
1136 + pReader->nData -= n; | |
1137 + pReader->pData += n; | |
1138 + n = getVarint32Safe(pReader->pData, &nSuffix, pReader->nData); | |
1139 + if( !n ) return SQLITE_CORRUPT_BKPT; | |
1140 + pReader->nData -= n; | |
1141 + pReader->pData += n; | |
1142 + if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT; | |
1143 + if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT; | |
1144 pReader->term.nData = nPrefix; | |
1145 - dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); | |
1146 + dataBufferAppend(&pReader->term, pReader->pData, nSuffix); | |
1147 | |
1148 - pReader->pData += n+nSuffix; | |
1149 - pReader->nData -= n+nSuffix; | |
1150 + pReader->pData += nSuffix; | |
1151 + pReader->nData -= nSuffix; | |
1152 } | |
1153 + return SQLITE_OK; | |
1154 } | |
1155 | |
1156 /* strcmp-style comparison of pReader's current term against pTerm. | |
1157 @@ -5133,14 +5326,19 @@ static int leavesReaderInit(fulltext_vtab *v, | |
1158 | |
1159 dataBufferInit(&pReader->rootData, 0); | |
1160 if( iStartBlockid==0 ){ | |
1161 + int rc; | |
1162 /* Corrupt if this can't be a leaf node. */ | |
1163 if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){ | |
1164 return SQLITE_CORRUPT_BKPT; | |
1165 } | |
1166 /* Entire leaf level fit in root data. */ | |
1167 dataBufferReplace(&pReader->rootData, pRootData, nRootData); | |
1168 - leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
1169 - &pReader->leafReader); | |
1170 + rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, | |
1171 + &pReader->leafReader); | |
1172 + if( rc!=SQLITE_OK ){ | |
1173 + dataBufferDestroy(&pReader->rootData); | |
1174 + return rc; | |
1175 + } | |
1176 }else{ | |
1177 sqlite3_stmt *s; | |
1178 int rc = sql_get_leaf_statement(v, idx, &s); | |
1179 @@ -5174,7 +5372,7 @@ static int leavesReaderInit(fulltext_vtab *v, | |
1180 if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){ | |
1181 rc = SQLITE_CORRUPT_BKPT; | |
1182 }else{ | |
1183 - leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
1184 + rc = leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
1185 } | |
1186 } | |
1187 | |
1188 @@ -5197,11 +5395,12 @@ static int leavesReaderInit(fulltext_vtab *v, | |
1189 ** end of the current leaf, step forward to the next leaf block. | |
1190 */ | |
1191 static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ | |
1192 + int rc; | |
1193 assert( !leavesReaderAtEnd(pReader) ); | |
1194 - leafReaderStep(&pReader->leafReader); | |
1195 + rc = leafReaderStep(&pReader->leafReader); | |
1196 + if( rc!=SQLITE_OK ) return rc; | |
1197 | |
1198 if( leafReaderAtEnd(&pReader->leafReader) ){ | |
1199 - int rc; | |
1200 if( pReader->rootData.pData ){ | |
1201 pReader->eof = 1; | |
1202 return SQLITE_OK; | |
1203 @@ -5216,6 +5415,7 @@ static int leavesReaderStep(fulltext_vtab *v, LeavesReader
*pReader){ | |
1204 if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){ | |
1205 return SQLITE_CORRUPT_BKPT; | |
1206 }else{ | |
1207 + LeafReader tmp; | |
1208 const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0); | |
1209 int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0); | |
1210 | |
1211 @@ -5224,8 +5424,10 @@ static int leavesReaderStep(fulltext_vtab *v, LeavesReade
r *pReader){ | |
1212 return SQLITE_CORRUPT_BKPT; | |
1213 } | |
1214 | |
1215 + rc = leafReaderInit(pLeafData, nLeafData, &tmp); | |
1216 + if( rc!=SQLITE_OK ) return rc; | |
1217 leafReaderDestroy(&pReader->leafReader); | |
1218 - leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); | |
1219 + pReader->leafReader = tmp; | |
1220 } | |
1221 } | |
1222 return SQLITE_OK; | |
1223 @@ -5334,13 +5536,26 @@ static int leavesReadersMerge(fulltext_vtab *v, | |
1224 DLReader dlReaders[MERGE_COUNT]; | |
1225 const char *pTerm = leavesReaderTerm(pReaders); | |
1226 int i, nTerm = leavesReaderTermBytes(pReaders); | |
1227 + int rc; | |
1228 | |
1229 assert( nReaders<=MERGE_COUNT ); | |
1230 | |
1231 for(i=0; i<nReaders; i++){ | |
1232 - dlrInit(&dlReaders[i], DL_DEFAULT, | |
1233 - leavesReaderData(pReaders+i), | |
1234 - leavesReaderDataBytes(pReaders+i)); | |
1235 + const char *pData = leavesReaderData(pReaders+i); | |
1236 + if( pData==NULL ){ | |
1237 + rc = SQLITE_CORRUPT_BKPT; | |
1238 + break; | |
1239 + } | |
1240 + rc = dlrInit(&dlReaders[i], DL_DEFAULT, | |
1241 + pData, | |
1242 + leavesReaderDataBytes(pReaders+i)); | |
1243 + if( rc!=SQLITE_OK ) break; | |
1244 + } | |
1245 + if( rc!=SQLITE_OK ){ | |
1246 + while( i-->0 ){ | |
1247 + dlrDestroy(&dlReaders[i]); | |
1248 + } | |
1249 + return rc; | |
1250 } | |
1251 | |
1252 return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); | |
1253 @@ -5444,12 +5659,14 @@ static int segmentMerge(fulltext_vtab *v, int iLevel){ | |
1254 } | |
1255 | |
1256 /* Accumulate the union of *acc and *pData into *acc. */ | |
1257 -static void docListAccumulateUnion(DataBuffer *acc, | |
1258 - const char *pData, int nData) { | |
1259 +static int docListAccumulateUnion(DataBuffer *acc, | |
1260 + const char *pData, int nData) { | |
1261 DataBuffer tmp = *acc; | |
1262 + int rc; | |
1263 dataBufferInit(acc, tmp.nData+nData); | |
1264 - docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | |
1265 + rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc); | |
1266 dataBufferDestroy(&tmp); | |
1267 + return rc; | |
1268 } | |
1269 | |
1270 /* TODO(shess) It might be interesting to explore different merge | |
1271 @@ -5491,8 +5708,13 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, LeavesR
eader *pReader, | |
1272 int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); | |
1273 if( c>0 ) break; /* Past any possible matches. */ | |
1274 if( c==0 ){ | |
1275 + int iBuffer, nData; | |
1276 const char *pData = leavesReaderData(pReader); | |
1277 - int iBuffer, nData = leavesReaderDataBytes(pReader); | |
1278 + if( pData==NULL ){ | |
1279 + rc = SQLITE_CORRUPT_BKPT; | |
1280 + break; | |
1281 + } | |
1282 + nData = leavesReaderDataBytes(pReader); | |
1283 | |
1284 /* Find the first empty buffer. */ | |
1285 for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ | |
1286 @@ -5538,11 +5760,13 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, Leaves
Reader *pReader, | |
1287 ** with pData/nData. | |
1288 */ | |
1289 dataBufferSwap(p, pAcc); | |
1290 - docListAccumulateUnion(pAcc, pData, nData); | |
1291 + rc = docListAccumulateUnion(pAcc, pData, nData); | |
1292 + if( rc!=SQLITE_OK ) goto err; | |
1293 | |
1294 /* Accumulate remaining doclists into pAcc. */ | |
1295 for(++p; p<pAcc; ++p){ | |
1296 - docListAccumulateUnion(pAcc, p->pData, p->nData); | |
1297 + rc = docListAccumulateUnion(pAcc, p->pData, p->nData); | |
1298 + if( rc!=SQLITE_OK ) goto err; | |
1299 | |
1300 /* dataBufferReset() could allow a large doclist to blow up | |
1301 ** our memory requirements. | |
1302 @@ -5567,13 +5791,15 @@ static int loadSegmentLeavesInt(fulltext_vtab *v, Leaves
Reader *pReader, | |
1303 if( out->nData==0 ){ | |
1304 dataBufferSwap(out, &(pBuffers[iBuffer])); | |
1305 }else{ | |
1306 - docListAccumulateUnion(out, pBuffers[iBuffer].pData, | |
1307 - pBuffers[iBuffer].nData); | |
1308 + rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData, | |
1309 + pBuffers[iBuffer].nData); | |
1310 + if( rc!=SQLITE_OK ) break; | |
1311 } | |
1312 } | |
1313 } | |
1314 } | |
1315 | |
1316 +err: | |
1317 while( nBuffers-- ){ | |
1318 dataBufferDestroy(&(pBuffers[nBuffers])); | |
1319 } | |
1320 @@ -5632,20 +5858,26 @@ static int loadSegmentLeaves(fulltext_vtab *v, | |
1321 ** node. Consider whether breaking symmetry is worthwhile. I suspect | |
1322 ** it is not worthwhile. | |
1323 */ | |
1324 -static void getChildrenContaining(const char *pData, int nData, | |
1325 - const char *pTerm, int nTerm, int isPrefix, | |
1326 - sqlite_int64 *piStartChild, | |
1327 - sqlite_int64 *piEndChild){ | |
1328 +static int getChildrenContaining(const char *pData, int nData, | |
1329 + const char *pTerm, int nTerm, int isPrefix, | |
1330 + sqlite_int64 *piStartChild, | |
1331 + sqlite_int64 *piEndChild){ | |
1332 InteriorReader reader; | |
1333 + int rc; | |
1334 | |
1335 assert( nData>1 ); | |
1336 assert( *pData!='\0' ); | |
1337 - interiorReaderInit(pData, nData, &reader); | |
1338 + rc = interiorReaderInit(pData, nData, &reader); | |
1339 + if( rc!=SQLITE_OK ) return rc; | |
1340 | |
1341 /* Scan for the first child which could contain pTerm/nTerm. */ | |
1342 while( !interiorReaderAtEnd(&reader) ){ | |
1343 if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; | |
1344 - interiorReaderStep(&reader); | |
1345 + rc = interiorReaderStep(&reader); | |
1346 + if( rc!=SQLITE_OK ){ | |
1347 + interiorReaderDestroy(&reader); | |
1348 + return rc; | |
1349 + } | |
1350 } | |
1351 *piStartChild = interiorReaderCurrentBlockid(&reader); | |
1352 | |
1353 @@ -5655,7 +5887,11 @@ static void getChildrenContaining(const char *pData, int
nData, | |
1354 */ | |
1355 while( !interiorReaderAtEnd(&reader) ){ | |
1356 if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; | |
1357 - interiorReaderStep(&reader); | |
1358 + rc = interiorReaderStep(&reader); | |
1359 + if( rc!=SQLITE_OK ){ | |
1360 + interiorReaderDestroy(&reader); | |
1361 + return rc; | |
1362 + } | |
1363 } | |
1364 *piEndChild = interiorReaderCurrentBlockid(&reader); | |
1365 | |
1366 @@ -5664,6 +5900,7 @@ static void getChildrenContaining(const char *pData, int n
Data, | |
1367 /* Children must ascend, and if !prefix, both must be the same. */ | |
1368 assert( *piEndChild>=*piStartChild ); | |
1369 assert( isPrefix || *piStartChild==*piEndChild ); | |
1370 + return rc; | |
1371 } | |
1372 | |
1373 /* Read block at iBlockid and pass it with other params to | |
1374 @@ -5709,8 +5946,12 @@ static int loadAndGetChildrenContaining( | |
1375 return SQLITE_CORRUPT_BKPT; | |
1376 } | |
1377 | |
1378 - getChildrenContaining(pData, nData, pTerm, nTerm, | |
1379 - isPrefix, piStartChild, piEndChild); | |
1380 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, | |
1381 + isPrefix, piStartChild, piEndChild); | |
1382 + if( rc!=SQLITE_OK ){ | |
1383 + sqlite3_reset(s); | |
1384 + return rc; | |
1385 + } | |
1386 } | |
1387 | |
1388 /* We expect only one row. We must execute another sqlite3_step() | |
1389 @@ -5741,8 +5982,9 @@ static int loadSegmentInt(fulltext_vtab *v, const char *pD
ata, int nData, | |
1390 /* Process pData as an interior node, then loop down the tree | |
1391 ** until we find the set of leaf nodes to scan for the term. | |
1392 */ | |
1393 - getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | |
1394 - &iStartChild, &iEndChild); | |
1395 + rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, | |
1396 + &iStartChild, &iEndChild); | |
1397 + if( rc!=SQLITE_OK ) return rc; | |
1398 while( iStartChild>iLeavesEnd ){ | |
1399 sqlite_int64 iNextStart, iNextEnd; | |
1400 rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, | |
1401 @@ -5812,16 +6054,21 @@ static int loadSegment(fulltext_vtab *v, const char *pDa
ta, int nData, | |
1402 DataBuffer merged; | |
1403 DLReader readers[2]; | |
1404 | |
1405 - dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | |
1406 - dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | |
1407 - dataBufferInit(&merged, out->nData+result.nData); | |
1408 - docListMerge(&merged, readers, 2); | |
1409 - dataBufferDestroy(out); | |
1410 - *out = merged; | |
1411 - dlrDestroy(&readers[0]); | |
1412 - dlrDestroy(&readers[1]); | |
1413 + rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); | |
1414 + if( rc==SQLITE_OK ){ | |
1415 + rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); | |
1416 + if( rc==SQLITE_OK ){ | |
1417 + dataBufferInit(&merged, out->nData+result.nData); | |
1418 + rc = docListMerge(&merged, readers, 2); | |
1419 + dataBufferDestroy(out); | |
1420 + *out = merged; | |
1421 + dlrDestroy(&readers[1]); | |
1422 + } | |
1423 + dlrDestroy(&readers[0]); | |
1424 + } | |
1425 } | |
1426 } | |
1427 + | |
1428 dataBufferDestroy(&result); | |
1429 return rc; | |
1430 } | |
1431 @@ -5862,6 +6109,7 @@ static int termSelect(fulltext_vtab *v, int iColumn, | |
1432 if( rc!=SQLITE_OK ) goto err; | |
1433 } | |
1434 if( rc==SQLITE_DONE ){ | |
1435 + rc = SQLITE_OK; | |
1436 if( doclist.nData!=0 ){ | |
1437 /* TODO(shess) The old term_select_all() code applied the column | |
1438 ** restrict as we merged segments, leading to smaller buffers. | |
1439 @@ -5869,10 +6117,9 @@ static int termSelect(fulltext_vtab *v, int iColumn, | |
1440 ** system is checked in. | |
1441 */ | |
1442 if( iColumn==v->nColumn) iColumn = -1; | |
1443 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
1444 - iColumn, iType, out); | |
1445 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
1446 + iColumn, iType, out); | |
1447 } | |
1448 - rc = SQLITE_OK; | |
1449 } | |
1450 | |
1451 err: | |
1452 @@ -6218,6 +6465,7 @@ static int optimizeInternal(fulltext_vtab *v, | |
1453 LeafWriter *pWriter){ | |
1454 int i, rc = SQLITE_OK; | |
1455 DataBuffer doclist, merged, tmp; | |
1456 + const char *pData; | |
1457 | |
1458 /* Order the readers. */ | |
1459 i = nReaders; | |
1460 @@ -6238,14 +6486,21 @@ static int optimizeInternal(fulltext_vtab *v, | |
1461 if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; | |
1462 } | |
1463 | |
1464 + pData = optLeavesReaderData(&readers[0]); | |
1465 + if( pData==NULL ){ | |
1466 + rc = SQLITE_CORRUPT_BKPT; | |
1467 + break; | |
1468 + } | |
1469 + | |
1470 /* Special-case for no merge. */ | |
1471 if( i==1 ){ | |
1472 /* Trim deletions from the doclist. */ | |
1473 dataBufferReset(&merged); | |
1474 - docListTrim(DL_DEFAULT, | |
1475 - optLeavesReaderData(&readers[0]), | |
1476 - optLeavesReaderDataBytes(&readers[0]), | |
1477 - -1, DL_DEFAULT, &merged); | |
1478 + rc = docListTrim(DL_DEFAULT, | |
1479 + pData, | |
1480 + optLeavesReaderDataBytes(&readers[0]), | |
1481 + -1, DL_DEFAULT, &merged); | |
1482 + if( rc!= SQLITE_OK ) break; | |
1483 }else{ | |
1484 DLReader dlReaders[MERGE_COUNT]; | |
1485 int iReader, nReaders; | |
1486 @@ -6253,9 +6508,10 @@ static int optimizeInternal(fulltext_vtab *v, | |
1487 /* Prime the pipeline with the first reader's doclist. After | |
1488 ** one pass index 0 will reference the accumulated doclist. | |
1489 */ | |
1490 - dlrInit(&dlReaders[0], DL_DEFAULT, | |
1491 - optLeavesReaderData(&readers[0]), | |
1492 - optLeavesReaderDataBytes(&readers[0])); | |
1493 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, | |
1494 + pData, | |
1495 + optLeavesReaderDataBytes(&readers[0])); | |
1496 + if( rc!=SQLITE_OK ) break; | |
1497 iReader = 1; | |
1498 | |
1499 assert( iReader<i ); /* Must execute the loop at least once. */ | |
1500 @@ -6263,24 +6519,35 @@ static int optimizeInternal(fulltext_vtab *v, | |
1501 /* Merge 16 inputs per pass. */ | |
1502 for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; | |
1503 iReader++, nReaders++ ){ | |
1504 - dlrInit(&dlReaders[nReaders], DL_DEFAULT, | |
1505 - optLeavesReaderData(&readers[iReader]), | |
1506 - optLeavesReaderDataBytes(&readers[iReader])); | |
1507 + pData = optLeavesReaderData(&readers[iReader]); | |
1508 + if( pData == NULL ){ | |
1509 + rc = SQLITE_CORRUPT_BKPT; | |
1510 + break; | |
1511 + } | |
1512 + rc = dlrInit(&dlReaders[nReaders], DL_DEFAULT, | |
1513 + pData, | |
1514 + optLeavesReaderDataBytes(&readers[iReader])); | |
1515 + if( rc != SQLITE_OK ) break; | |
1516 } | |
1517 | |
1518 /* Merge doclists and swap result into accumulator. */ | |
1519 - dataBufferReset(&merged); | |
1520 - docListMerge(&merged, dlReaders, nReaders); | |
1521 - tmp = merged; | |
1522 - merged = doclist; | |
1523 - doclist = tmp; | |
1524 + if( rc==SQLITE_OK ){ | |
1525 + dataBufferReset(&merged); | |
1526 + rc = docListMerge(&merged, dlReaders, nReaders); | |
1527 + tmp = merged; | |
1528 + merged = doclist; | |
1529 + doclist = tmp; | |
1530 + } | |
1531 | |
1532 while( nReaders-- > 0 ){ | |
1533 dlrDestroy(&dlReaders[nReaders]); | |
1534 } | |
1535 | |
1536 + if( rc!=SQLITE_OK ) goto err; | |
1537 + | |
1538 /* Accumulated doclist to reader 0 for next pass. */ | |
1539 - dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | |
1540 + rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); | |
1541 + if( rc!=SQLITE_OK ) goto err; | |
1542 } | |
1543 | |
1544 /* Destroy reader that was left in the pipeline. */ | |
1545 @@ -6288,8 +6555,9 @@ static int optimizeInternal(fulltext_vtab *v, | |
1546 | |
1547 /* Trim deletions from the doclist. */ | |
1548 dataBufferReset(&merged); | |
1549 - docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
1550 - -1, DL_DEFAULT, &merged); | |
1551 + rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, | |
1552 + -1, DL_DEFAULT, &merged); | |
1553 + if( rc!=SQLITE_OK ) goto err; | |
1554 } | |
1555 | |
1556 /* Only pass doclists with hits (skip if all hits deleted). */ | |
1557 @@ -6628,16 +6896,19 @@ static void createDoclistResult(sqlite3_context *pContex
t, | |
1558 const char *pData, int nData){ | |
1559 DataBuffer dump; | |
1560 DLReader dlReader; | |
1561 + int rc; | |
1562 | |
1563 assert( pData!=NULL && nData>0 ); | |
1564 | |
1565 + rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData); | |
1566 + if( rc!=SQLITE_OK ) return; | |
1567 dataBufferInit(&dump, 0); | |
1568 - dlrInit(&dlReader, DL_DEFAULT, pData, nData); | |
1569 - for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ | |
1570 + for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){ | |
1571 char buf[256]; | |
1572 PLReader plReader; | |
1573 | |
1574 - plrInit(&plReader, &dlReader); | |
1575 + rc = plrInit(&plReader, &dlReader); | |
1576 + if( rc!=SQLITE_OK ) break; | |
1577 if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ | |
1578 sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); | |
1579 dataBufferAppend(&dump, buf, strlen(buf)); | |
1580 @@ -6648,7 +6919,8 @@ static void createDoclistResult(sqlite3_context *pContext, | |
1581 dlrDocid(&dlReader), iColumn); | |
1582 dataBufferAppend(&dump, buf, strlen(buf)); | |
1583 | |
1584 - for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ | |
1585 + for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){ | |
1586 + if( rc!=SQLITE_OK ) break; | |
1587 if( plrColumn(&plReader)!=iColumn ){ | |
1588 iColumn = plrColumn(&plReader); | |
1589 sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); | |
1590 @@ -6669,6 +6941,7 @@ static void createDoclistResult(sqlite3_context *pContext, | |
1591 dataBufferAppend(&dump, buf, strlen(buf)); | |
1592 } | |
1593 plrDestroy(&plReader); | |
1594 + if( rc!= SQLITE_OK ) break; | |
1595 | |
1596 assert( dump.nData>0 ); | |
1597 dump.nData--; /* Overwrite trailing space. */ | |
1598 @@ -6677,6 +6950,10 @@ static void createDoclistResult(sqlite3_context *pContext
, | |
1599 } | |
1600 } | |
1601 dlrDestroy(&dlReader); | |
1602 + if( rc!=SQLITE_OK ){ | |
1603 + dataBufferDestroy(&dump); | |
1604 + return; | |
1605 + } | |
1606 | |
1607 assert( dump.nData>0 ); | |
1608 dump.nData--; /* Overwrite trailing space. */ | |
1609 -- | |
1610 2.2.1 | |
1611 | |
OLD | NEW |