/ Check-in [c3c15d20]
Login

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

Overview
Comment:Avoid ever writing before the start of an allocated buffer in the DIRECT_OVERFLOW_READ code. Fix for [e3a290961a6].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c3c15d20c6913811956a5041c959a56ca4eeb5eb
User & Date: dan 2014-10-01 12:01:10
References
2015-05-21
17:21
Avoid ever writing before the start of an allocated buffer in the DIRECT_OVERFLOW_READ code. Fix for [e3a290961a6]. Cherrypick of [c3c15d20c691]. check-in: 31b13eb5 user: dan tags: branch-3.8.6
2014-10-01
12:02 Closed ticket [e3a29096]: out-of-bounds write when using non-default malloc implementation and SQLITE_DIRECT_OVERFLOW_READ plus 6 other changes artifact: 347802e2 user: dan
Context
2015-05-21
17:21
Avoid ever writing before the start of an allocated buffer in the DIRECT_OVERFLOW_READ code. Fix for [e3a290961a6]. Cherrypick of [c3c15d20c691]. check-in: 31b13eb5 user: dan tags: branch-3.8.6
2014-10-01
13:17
Show the TK_DOT operator in the TreeView debugging output. No changes to production code. check-in: 07c89940 user: drh tags: trunk
12:01
Avoid ever writing before the start of an allocated buffer in the DIRECT_OVERFLOW_READ code. Fix for [e3a290961a6]. check-in: c3c15d20 user: dan tags: trunk
2014-09-30
19:04
Improvements to the new syntax-tree output routines: Omit the "END SELECT" mark and instead terminate the graph at the last item. Increase the maximum tree depth to 100. check-in: 5ce05757 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

  4018   4018   ){
  4019   4019     unsigned char *aPayload;
  4020   4020     int rc = SQLITE_OK;
  4021   4021     int iIdx = 0;
  4022   4022     MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
  4023   4023     BtShared *pBt = pCur->pBt;                  /* Btree this cursor belongs to */
  4024   4024   #ifdef SQLITE_DIRECT_OVERFLOW_READ
         4025  +  unsigned char * const pBufStart = pBuf;
  4025   4026     int bEnd;                                 /* True if reading to end of data */
  4026   4027   #endif
  4027   4028   
  4028   4029     assert( pPage );
  4029   4030     assert( pCur->eState==CURSOR_VALID );
  4030   4031     assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
  4031   4032     assert( cursorHoldsMutex(pCur) );
................................................................................
  4145   4146           **
  4146   4147           **   1) this is a read operation, and 
  4147   4148           **   2) data is required from the start of this overflow page, and
  4148   4149           **   3) the database is file-backed, and
  4149   4150           **   4) there is no open write-transaction, and
  4150   4151           **   5) the database is not a WAL database,
  4151   4152           **   6) all data from the page is being read.
         4153  +        **   7) at least 4 bytes have already been read into the output buffer 
  4152   4154           **
  4153   4155           ** then data can be read directly from the database file into the
  4154   4156           ** output buffer, bypassing the page-cache altogether. This speeds
  4155   4157           ** up loading large records that span many overflow pages.
  4156   4158           */
  4157   4159           if( (eOp&0x01)==0                                      /* (1) */
  4158   4160            && offset==0                                          /* (2) */
  4159   4161            && (bEnd || a==ovflSize)                              /* (6) */
  4160   4162            && pBt->inTransaction==TRANS_READ                     /* (4) */
  4161   4163            && (fd = sqlite3PagerFile(pBt->pPager))->pMethods     /* (3) */
  4162   4164            && pBt->pPage1->aData[19]==0x01                       /* (5) */
         4165  +         && &pBuf[-4]>=pBufStart                               /* (7) */
  4163   4166           ){
  4164   4167             u8 aSave[4];
  4165   4168             u8 *aWrite = &pBuf[-4];
         4169  +          assert( aWrite>=pBufStart );                         /* hence (7) */
  4166   4170             memcpy(aSave, aWrite, 4);
  4167   4171             rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
  4168   4172             nextPage = get4byte(aWrite);
  4169   4173             memcpy(aWrite, aSave, 4);
  4170   4174           }else
  4171   4175   #endif
  4172   4176   

Added test/ovfl.test.

            1  +# 2014 October 01
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is testing the SQLITE_DIRECT_OVERFLOW_READ logic.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set testprefix ovfl
           18  +
           19  +# Populate table t2:
           20  +#
           21  +#   CREATE TABLE t1(c1 TEXT, c2 TEXT);
           22  +#
           23  +# with 2000 rows. In each row, c2 spans multiple overflow pages. The text
           24  +# value of c1 ranges in size from 1 to 2000 bytes. The idea is to create
           25  +# at least one row where the first byte of c2 is also the first byte of
           26  +# an overflow page. This was at one point exposing an obscure bug in the
           27  +# SQLITE_DIRECT_OVERFLOW_READ logic.
           28  +#
           29  +do_test 1.1 {
           30  +  set c2 [string repeat abcdefghij 200]
           31  +  execsql {
           32  +    PRAGMA cache_size = 10;
           33  +    CREATE TABLE t1(c1 TEXT, c2 TEXT);
           34  +    BEGIN;
           35  +  }
           36  +  for {set i 1} {$i <= 2000} {incr i} {
           37  +    set c1 [string repeat . $i]
           38  +    execsql { INSERT INTO t1 VALUES($c1, $c2) }
           39  +  }
           40  +  execsql COMMIT
           41  +} {}
           42  +
           43  +do_execsql_test 1.2 {
           44  +  SELECT sum(length(c2)) FROM t1;
           45  +} [expr 2000 * 2000]
           46  +
           47  +finish_test
           48  +
           49  +