/ Check-in [7aecabac]
Login

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

Overview
Comment:Fix a case where database corruption was causing an invalid reference. (CVS 5484)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:7aecabacf924ad8c1f9f4e707d0c56e433e3a434
User & Date: danielk1977 2008-07-26 18:26:10
Context
2008-07-26
18:47
Remove a branch that could not be taken from OP_IsUnique. (CVS 5485) check-in: 75c2a532 user: danielk1977 tags: trunk
18:26
Fix a case where database corruption was causing an invalid reference. (CVS 5484) check-in: 7aecabac user: danielk1977 tags: trunk
2008-07-25
16:39
Add an SQLITE_OMIT_LOCALTIME around the "utc" modifier in date/time functions. (CVS 5483) check-in: 71486e93 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
3132
3133
3134
3135
3136
3137
3138
3139



3140
3141
3142
3143
3144
3145
3146
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.763 2008/07/23 21:07:25 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
................................................................................

    /* Make sure K is a string and make zKey point to K
    */
    assert( pK->flags & MEM_Blob );
    zKey = pK->z;
    nKey = pK->n;

    szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);



    len = nKey-szRowid;

    /* Search for an entry in P1 where all but the last four bytes match K.
    ** If there is no such entry, jump immediately to P2.
    */
    assert( pCx->deferredMoveto==0 );
    pCx->cacheStatus = CACHE_STALE;







|







 







|
>
>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.764 2008/07/26 18:26:10 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
................................................................................

    /* Make sure K is a string and make zKey point to K
    */
    assert( pK->flags & MEM_Blob );
    zKey = pK->z;
    nKey = pK->n;

    rc = sqlite3VdbeIdxRowidLen((u8*)zKey, nKey, &szRowid);
    if( rc!=SQLITE_OK ){
      goto abort_due_to_error;
    }
    len = nKey-szRowid;

    /* Search for an entry in P1 where all but the last four bytes match K.
    ** If there is no such entry, jump immediately to P2.
    */
    assert( pCx->deferredMoveto==0 );
    pCx->cacheStatus = CACHE_STALE;

Changes to src/vdbeInt.h.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
*************************************************************************
** This is the header file for information that is private to the
** VDBE.  This information used to all be at the top of the single
** source code file "vdbe.c".  When that file became too big (over
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
**
** $Id: vdbeInt.h,v 1.149 2008/06/25 00:12:41 drh Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_

/*
** intToKey() and keyToInt() used to transform the rowid.  But with
** the latest versions of the design they are no-ops.
................................................................................
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*,UnpackedRecord *,int,const unsigned char*,int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeIdxRowidLen(const u8*);
int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*);
int sqlite3VdbeChangeEncoding(Mem *, int);
int sqlite3VdbeMemTooBig(Mem*);
int sqlite3VdbeMemCopy(Mem*, const Mem*);
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);







|







 







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
*************************************************************************
** This is the header file for information that is private to the
** VDBE.  This information used to all be at the top of the single
** source code file "vdbe.c".  When that file became too big (over
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
**
** $Id: vdbeInt.h,v 1.150 2008/07/26 18:26:10 danielk1977 Exp $
*/
#ifndef _VDBEINT_H_
#define _VDBEINT_H_

/*
** intToKey() and keyToInt() used to transform the rowid.  But with
** the latest versions of the design they are no-ops.
................................................................................
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*,UnpackedRecord *,int,const unsigned char*,int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeIdxRowidLen(const u8*, int, int*);
int sqlite3VdbeExec(Vdbe*);
int sqlite3VdbeList(Vdbe*);
int sqlite3VdbeHalt(Vdbe*);
int sqlite3VdbeChangeEncoding(Mem *, int);
int sqlite3VdbeMemTooBig(Mem*);
int sqlite3VdbeMemCopy(Mem*, const Mem*);
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);

Changes to src/vdbeaux.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361



2362
2363

2364
2365
2366
2367
2368
2369
2370
....
2425
2426
2427
2428
2429
2430
2431
2432

2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.399 2008/07/22 05:18:01 shane Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"



................................................................................

/*
** The argument is an index entry composed using the OP_MakeRecord opcode.
** The last entry in this record should be an integer (specifically
** an integer rowid).  This routine returns the number of bytes in
** that integer.
*/
int sqlite3VdbeIdxRowidLen(const u8 *aKey){
  u32 szHdr;        /* Size of the header */
  u32 typeRowid;    /* Serial type of the rowid */

  (void)getVarint32(aKey, szHdr);



  (void)getVarint32(&aKey[szHdr-1], typeRowid);
  return sqlite3VdbeSerialTypeLen(typeRowid);

}
  

/*
** pCur points at an index entry created using the OP_MakeRecord opcode.
** Read the rowid (the last field in the record) and store it in *rowid.
** Return SQLITE_OK if everything works, or an error code otherwise.
................................................................................
  if( nCellKey<=0 ){
    *res = 0;
    return SQLITE_OK;
  }
  m.db = 0;
  m.flags = 0;
  m.zMalloc = 0;
  rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m);

  if( rc ){
    return rc;
  }
  lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
  if( !pUnpacked ){
    pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey,
                                zSpace, sizeof(zSpace));
  }else{
    pRec = pUnpacked;
  }
  if( pRec==0 ){







|







 







|




>
>
>

|
>







 







|
>
|


<







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
....
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
....
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440

2441
2442
2443
2444
2445
2446
2447
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.400 2008/07/26 18:26:10 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"



................................................................................

/*
** The argument is an index entry composed using the OP_MakeRecord opcode.
** The last entry in this record should be an integer (specifically
** an integer rowid).  This routine returns the number of bytes in
** that integer.
*/
int sqlite3VdbeIdxRowidLen(const u8 *aKey, int nKey, int *pRowidLen){
  u32 szHdr;        /* Size of the header */
  u32 typeRowid;    /* Serial type of the rowid */

  (void)getVarint32(aKey, szHdr);
  if( szHdr>nKey ){
    return SQLITE_CORRUPT_BKPT;
  }
  (void)getVarint32(&aKey[szHdr-1], typeRowid);
  *pRowidLen = sqlite3VdbeSerialTypeLen(typeRowid);
  return SQLITE_OK;
}
  

/*
** pCur points at an index entry created using the OP_MakeRecord opcode.
** Read the rowid (the last field in the record) and store it in *rowid.
** Return SQLITE_OK if everything works, or an error code otherwise.
................................................................................
  if( nCellKey<=0 ){
    *res = 0;
    return SQLITE_OK;
  }
  m.db = 0;
  m.flags = 0;
  m.zMalloc = 0;
  if( (rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m))
   || (rc = sqlite3VdbeIdxRowidLen((u8*)m.z, m.n, &lenRowid))
  ){
    return rc;
  }

  if( !pUnpacked ){
    pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey,
                                zSpace, sizeof(zSpace));
  }else{
    pRec = pUnpacked;
  }
  if( pRec==0 ){

Changes to test/corrupt7.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
68
69
70
71
72
73
74



























75
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.  It specifically focuses
# on corrupt cell offsets in a btree page.
#
# $Id: corrupt7.test,v 1.3 2008/07/25 14:53:17 drh Exp $

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

# We must have the page_size pragma for these tests to work.
#
ifcapable !pager_pragmas {
................................................................................
  db close
  hexio_write test.db 1062 04
  sqlite3 db test.db
  db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Corruption detected in cell 15 on page 2}}




























finish_test







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.  It specifically focuses
# on corrupt cell offsets in a btree page.
#
# $Id: corrupt7.test,v 1.4 2008/07/26 18:26:10 danielk1977 Exp $

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

# We must have the page_size pragma for these tests to work.
#
ifcapable !pager_pragmas {
................................................................................
  db close
  hexio_write test.db 1062 04
  sqlite3 db test.db
  db eval {PRAGMA integrity_check(1)}
} {{*** in database main ***
Corruption detected in cell 15 on page 2}}

do_test corrupt7-3.1 {
  execsql {
    DROP TABLE t1;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 'one');
    INSERT INTO t1 VALUES(100, 'one hundred');
    INSERT INTO t1 VALUES(100000, 'one hundred thousand');
    CREATE INDEX i1 ON t1(b);
  }
  db close

  # Locate the 3rd cell in the index.
  set cell_offset [hexio_get_int [hexio_read test.db [expr 1024*2 + 12] 2]]
  incr cell_offset [expr 1024*2]
  incr cell_offset 1

  # This write corrupts the "header-size" field of the database record
  # stored in the index cell. At one point this was causing sqlite to 
  # reference invalid memory.
  hexio_write test.db $cell_offset FFFF7F
  
  sqlite3 db test.db
  catchsql {
    SELECT b FROM t1 WHERE b > 'o' AND b < 'p';
  }
} {1 {database disk image is malformed}}

finish_test