Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / sqlite / src / src / recover.c
index 6430c8b..097c920 100644 (file)
@@ -653,12 +653,28 @@ static void interiorCursorSetPage(RecoverInteriorCursor *pCursor,
   pCursor->iChild = 0;
 
   /* A child for each cell, plus one in the header. */
-  /* TODO(shess): Sanity-check the count?  Page header plus per-cell
-   * cost of 16-bit offset, 32-bit page number, and one varint
-   * (minimum 1 byte).
-   */
   pCursor->nChildren = decodeUnsigned16(PageHeader(pPage) +
                                         kiPageCellCountOffset) + 1;
+
+  /* Each child requires a 16-bit offset from an array after the header,
+   * and each child contains a 32-bit page number and at least a varint
+   * (min size of one byte).  The final child page is in the header.  So
+   * the maximum value for nChildren is:
+   *   (nPageSize - kiPageInteriorHeaderBytes) /
+   *      (sizeof(uint16) + sizeof(uint32) + 1) + 1
+   */
+  /* TODO(shess): This count is very unlikely to be corrupted in
+   * isolation, so seeing this could signal to skip the page.  OTOH, I
+   * can't offhand think of how to get here unless this or the page-type
+   * byte is corrupted.  Could be an overflow page, but it would require
+   * a very large database.
+   */
+  const unsigned knMinCellLength = 2 + 4 + 1;
+  unsigned nMaxChildren =
+      (pCursor->nPageSize - kiPageInteriorHeaderBytes) / knMinCellLength + 1;
+  if (pCursor->nChildren > nMaxChildren) {
+    pCursor->nChildren = nMaxChildren;
+  }
 }
 
 static int interiorCursorCreate(RecoverInteriorCursor *pParent,
@@ -1275,6 +1291,7 @@ static int ValidateError(){
 /* Setup the cursor for reading the information from cell iCell. */
 static int leafCursorCellDecode(RecoverLeafCursor *pCursor){
   const unsigned char *pPageHeader;  /* Header of current page. */
+  const unsigned char *pPageEnd;     /* Byte after end of current page. */
   const unsigned char *pCellOffsets; /* Pointer to page's cell offsets. */
   unsigned iCellOffset;              /* Offset of current cell (iCell). */
   const unsigned char *pCell;        /* Pointer to data at iCellOffset. */
@@ -1297,6 +1314,10 @@ static int leafCursorCellDecode(RecoverLeafCursor *pCursor){
   /* Find the offset to the row. */
   pPageHeader = PageHeader(pCursor->pPage);
   pCellOffsets = pPageHeader + knPageLeafHeaderBytes;
+  pPageEnd = PageData(pCursor->pPage, pCursor->nPageSize);
+  if( pCellOffsets + pCursor->iCell*2 + 2 > pPageEnd ){
+    return ValidateError();
+  }
   iCellOffset = decodeUnsigned16(pCellOffsets + pCursor->iCell*2);
   if( iCellOffset>=pCursor->nPageSize ){
     return ValidateError();
@@ -1338,7 +1359,7 @@ static int leafCursorCellDecode(RecoverLeafCursor *pCursor){
 
   /* Check that no other cell starts within this cell. */
   iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes;
-  for( i=0; i<pCursor->nCells; ++i ){
+  for( i=0; i<pCursor->nCells && pCellOffsets + i*2 + 2 <= pPageEnd; ++i ){
     const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2);
     if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){
       return ValidateError();
@@ -1627,6 +1648,12 @@ static int recoverOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   pCursor->pLeafCursor = pLeafCursor;
   pCursor->iEncoding = iEncoding;
 
+  /* If no leaf pages were found, empty result set. */
+  /* TODO(shess): leafCursorNextValidCell() would return SQLITE_ROW or
+   * SQLITE_DONE to indicate whether there is further data to consider.
+   */
+  pCursor->bEOF = (pLeafCursor->pPage==NULL);
+
   *ppCursor = (sqlite3_vtab_cursor*)pCursor;
   return SQLITE_OK;
 }
@@ -1715,8 +1742,14 @@ static int recoverFilter(
 
   FNENTRY();
 
-  /* Load the first cell, and iterate forward if it's not valid. */
-  /* TODO(shess): What happens if no cells at all are valid? */
+  /* There were no valid leaf pages in the table. */
+  if( pCursor->bEOF ){
+    return SQLITE_OK;
+  }
+
+  /* Load the first cell, and iterate forward if it's not valid.  If no cells at
+   * all are valid, recoverNext() sets bEOF and returns appropriately.
+   */
   rc = leafCursorCellDecode(pCursor->pLeafCursor);
   if( rc!=SQLITE_OK || recoverValidateLeafCell(pRecover, pCursor)!=SQLITE_OK ){
     return recoverNext(pVtabCursor);