/ Check-in [15e4f63d]
Login

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

Overview
Comment:Add a new sqlite3_test_control() that indicates that database files are always well-formed. Use this during testing to enable assert() statements that prove conditions that are always true for well-formed databases.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:15e4f63d1f3cbcd0aa789fd3e460cd6e4d3338f9
User & Date: drh 2013-11-29 15:06:27
Context
2013-11-29
15:39
Change the name of the CORRUPTIBLE macro to CORRUPT_DB. check-in: f865be10 user: drh tags: trunk
15:06
Add a new sqlite3_test_control() that indicates that database files are always well-formed. Use this during testing to enable assert() statements that prove conditions that are always true for well-formed databases. check-in: 15e4f63d user: drh tags: trunk
2013-11-28
19:28
Update a few test cases to account for the new error message formats. check-in: 65a5bce3 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/global.c.

   144    144   SQLITE_WSD struct Sqlite3Config sqlite3Config = {
   145    145      SQLITE_DEFAULT_MEMSTATUS,  /* bMemstat */
   146    146      1,                         /* bCoreMutex */
   147    147      SQLITE_THREADSAFE==1,      /* bFullMutex */
   148    148      SQLITE_USE_URI,            /* bOpenUri */
   149    149      SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
   150    150      0x7ffffffe,                /* mxStrlen */
          151  +   0,                         /* neverCorrupt */
   151    152      128,                       /* szLookaside */
   152    153      500,                       /* nLookaside */
   153    154      {0,0,0,0,0,0,0,0},         /* m */
   154    155      {0,0,0,0,0,0,0,0,0},       /* mutex */
   155    156      {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
   156    157      (void*)0,                  /* pHeap */
   157    158      0,                         /* nHeap */
................................................................................
   178    179      0,                         /* pLogArg */
   179    180      0,                         /* bLocaltimeFault */
   180    181   #ifdef SQLITE_ENABLE_SQLLOG
   181    182      0,                         /* xSqllog */
   182    183      0                          /* pSqllogArg */
   183    184   #endif
   184    185   };
   185         -
   186    186   
   187    187   /*
   188    188   ** Hash table for global functions - functions common to all
   189    189   ** database connections.  After initialization, this table is
   190    190   ** read-only.
   191    191   */
   192    192   SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;

Changes to src/main.c.

  3291   3291       case SQLITE_TESTCTRL_EXPLAIN_STMT: {
  3292   3292         sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*);
  3293   3293         const char **pzRet = va_arg(ap, const char**);
  3294   3294         *pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt);
  3295   3295         break;
  3296   3296       }
  3297   3297   #endif
         3298  +
         3299  +    /*   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int);
         3300  +    **
         3301  +    ** Set or clear a flag that indicates that the database file is always well-
         3302  +    ** formed and never corrupt.  This flag is clear by default, indicating that
         3303  +    ** database files might have arbitrary corruption.  Setting the flag during
         3304  +    ** testing causes certain assert() statements in the code to be activated
         3305  +    ** that demonstrat invariants on well-formed database files.
         3306  +    */
         3307  +    case SQLITE_TESTCTRL_NEVER_CORRUPT: {
         3308  +      sqlite3Config.neverCorrupt = va_arg(ap, int);
         3309  +      break;
         3310  +    }
  3298   3311   
  3299   3312     }
  3300   3313     va_end(ap);
  3301   3314   #endif /* SQLITE_OMIT_BUILTIN_TEST */
  3302   3315     return rc;
  3303   3316   }
  3304   3317   

Changes to src/sqlite.h.in.

  6065   6065   #define SQLITE_TESTCTRL_ALWAYS                  13
  6066   6066   #define SQLITE_TESTCTRL_RESERVE                 14
  6067   6067   #define SQLITE_TESTCTRL_OPTIMIZATIONS           15
  6068   6068   #define SQLITE_TESTCTRL_ISKEYWORD               16
  6069   6069   #define SQLITE_TESTCTRL_SCRATCHMALLOC           17
  6070   6070   #define SQLITE_TESTCTRL_LOCALTIME_FAULT         18
  6071   6071   #define SQLITE_TESTCTRL_EXPLAIN_STMT            19
  6072         -#define SQLITE_TESTCTRL_LAST                    19
         6072  +#define SQLITE_TESTCTRL_NEVER_CORRUPT           20
         6073  +#define SQLITE_TESTCTRL_LAST                    20
  6073   6074   
  6074   6075   /*
  6075   6076   ** CAPI3REF: SQLite Runtime Status
  6076   6077   **
  6077   6078   ** ^This interface is used to retrieve runtime status information
  6078   6079   ** about the performance of SQLite, and optionally to reset various
  6079   6080   ** highwater marks.  ^The first argument is an integer code for

Changes to src/sqliteInt.h.

  2534   2534   struct Sqlite3Config {
  2535   2535     int bMemstat;                     /* True to enable memory status */
  2536   2536     int bCoreMutex;                   /* True to enable core mutexing */
  2537   2537     int bFullMutex;                   /* True to enable full mutexing */
  2538   2538     int bOpenUri;                     /* True to interpret filenames as URIs */
  2539   2539     int bUseCis;                      /* Use covering indices for full-scans */
  2540   2540     int mxStrlen;                     /* Maximum string length */
         2541  +  int neverCorrupt;                 /* Database is always well-formed */
  2541   2542     int szLookaside;                  /* Default lookaside buffer size */
  2542   2543     int nLookaside;                   /* Default lookaside buffer count */
  2543   2544     sqlite3_mem_methods m;            /* Low-level memory allocation interface */
  2544   2545     sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
  2545   2546     sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
  2546   2547     void *pHeap;                      /* Heap storage space */
  2547   2548     int nHeap;                        /* Size of pHeap[] */
................................................................................
  2570   2571     int bLocaltimeFault;              /* True to fail localtime() calls */
  2571   2572   #ifdef SQLITE_ENABLE_SQLLOG
  2572   2573     void(*xSqllog)(void*,sqlite3*,const char*, int);
  2573   2574     void *pSqllogArg;
  2574   2575   #endif
  2575   2576   };
  2576   2577   
         2578  +/*
         2579  +** This macro is used inside of assert() statements to indicate that
         2580  +** the assert is only valid on a well-formed database.  Instead of:
         2581  +**
         2582  +**     assert( X );
         2583  +**
         2584  +** One writes:
         2585  +**
         2586  +**     assert( X || CORRUPTIBLE );
         2587  +**
         2588  +** CORRUPTIBLE is true during normal operation.  But for many test cases,
         2589  +** it is set to false using a sqlite3_test_control().  This enables assert()
         2590  +** statements to prove things that are always true for well-formed
         2591  +** databases.
         2592  +*/
         2593  +#define CORRUPTIBLE  (sqlite3Config.neverCorrupt==0)
         2594  +
  2577   2595   /*
  2578   2596   ** Context pointer passed down through the tree-walk.
  2579   2597   */
  2580   2598   struct Walker {
  2581   2599     int (*xExprCallback)(Walker*, Expr*);     /* Callback for expressions */
  2582   2600     int (*xSelectCallback)(Walker*,Select*);  /* Callback for SELECTs */
  2583   2601     Parse *pParse;                            /* Parser context.  */

Changes to src/test1.c.

  5448   5448     Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  5449   5449     int objc,              /* Number of arguments */
  5450   5450     Tcl_Obj *CONST objv[]  /* Command arguments */
  5451   5451   ){
  5452   5452     sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET);
  5453   5453     return TCL_OK;
  5454   5454   }
         5455  +
         5456  +/*
         5457  +** tclcmd:  database_may_be_corrupt
         5458  +**
         5459  +** Indicate that database files might be corrupt.  In other words, set the normal
         5460  +** state of operation.
         5461  +*/
         5462  +static int database_may_be_corrupt(
         5463  +  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
         5464  +  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
         5465  +  int objc,              /* Number of arguments */
         5466  +  Tcl_Obj *CONST objv[]  /* Command arguments */
         5467  +){
         5468  +  sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0);
         5469  +  return TCL_OK;
         5470  +}
         5471  +/*
         5472  +** tclcmd:  database_never_corrupt
         5473  +**
         5474  +** Indicate that database files are always well-formed.  This enables extra assert()
         5475  +** statements that test conditions that are always true for well-formed databases.
         5476  +*/
         5477  +static int database_never_corrupt(
         5478  +  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
         5479  +  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
         5480  +  int objc,              /* Number of arguments */
         5481  +  Tcl_Obj *CONST objv[]  /* Command arguments */
         5482  +){
         5483  +  sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1);
         5484  +  return TCL_OK;
         5485  +}
  5455   5486   
  5456   5487   /*
  5457   5488   ** tclcmd:  pcache_stats
  5458   5489   */
  5459   5490   static int test_pcache_stats(
  5460   5491     ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  5461   5492     Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
................................................................................
  6327   6358        { "sqlite3_enable_load_extension", test_enable_load,        0},
  6328   6359        { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
  6329   6360        { "sqlite3_limit",                 test_limit,                 0},
  6330   6361   
  6331   6362        { "save_prng_state",               save_prng_state,    0 },
  6332   6363        { "restore_prng_state",            restore_prng_state, 0 },
  6333   6364        { "reset_prng_state",              reset_prng_state,   0 },
         6365  +     { "database_never_corrupt",        database_never_corrupt, 0},
         6366  +     { "database_may_be_corrupt",       database_may_be_corrupt, 0},
  6334   6367        { "optimization_control",          optimization_control,0},
  6335   6368   #if SQLITE_OS_WIN
  6336   6369        { "lock_win32_file",               win32_file_lock,    0 },
  6337   6370        { "exists_win32_path",             win32_exists_path,  0 },
  6338   6371        { "find_win32_file",               win32_find_file,    0 },
  6339   6372        { "delete_win32_file",             win32_delete_file,  0 },
  6340   6373        { "make_win32_dir",                win32_mkdir,        0 },

Changes to src/vdbeaux.c.

  3108   3108     ** impact, since this routine is a very high runner.  And so, we choose
  3109   3109     ** to ignore the compiler warnings and leave this variable uninitialized.
  3110   3110     */
  3111   3111     /*  mem1.u.i = 0;  // not needed, here to silence compiler warning */
  3112   3112     
  3113   3113     idx1 = getVarint32(aKey1, szHdr1);
  3114   3114     d1 = szHdr1;
  3115         -  assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField );
         3115  +  assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPTIBLE );
  3116   3116     assert( pKeyInfo->aSortOrder!=0 );
         3117  +  assert( (idx1<=szHdr1 && i<pPKey2->nField) || CORRUPTIBLE );
  3117   3118     do{
  3118   3119       u32 serial_type1;
  3119   3120   
  3120   3121       /* Read the serial types for the next element in each key. */
  3121   3122       idx1 += getVarint32( aKey1+idx1, serial_type1 );
  3122   3123   
  3123   3124       /* Verify that there is enough key space remaining to avoid

Changes to test/corrupt.test.

    20     20   set testdir [file dirname $argv0]
    21     21   source $testdir/tester.tcl
    22     22   
    23     23   # Do not use a codec for tests in this file, as the database file is
    24     24   # manipulated directly using tcl scripts (using the [hexio_write] command).
    25     25   #
    26     26   do_not_use_codec
           27  +
           28  +# These tests deal with corrupt database files
           29  +#
           30  +database_may_be_corrupt
    27     31   
    28     32   # Construct a large database for testing.
    29     33   #
    30     34   do_test corrupt-1.1 {
    31     35     execsql {
    32     36       BEGIN;
    33     37       CREATE TABLE t1(x);

Changes to test/corrupt2.test.

    18     18   set testdir [file dirname $argv0]
    19     19   source $testdir/tester.tcl
    20     20   
    21     21   # Do not use a codec for tests in this file, as the database file is
    22     22   # manipulated directly using tcl scripts (using the [hexio_write] command).
    23     23   #
    24     24   do_not_use_codec
           25  +
           26  +# These tests deal with corrupt database files
           27  +#
           28  +database_may_be_corrupt
    25     29   
    26     30   set presql ""
    27     31   catch { set presql "$::G(perm:presql);" }
    28     32   unset -nocomplain ::G(perm:presql)
    29     33   
    30     34   # The following tests - corrupt2-1.* - create some databases corrupted in
    31     35   # specific ways and ensure that SQLite detects them as corrupt.

Changes to test/corrupt3.test.

    18     18   set testdir [file dirname $argv0]
    19     19   source $testdir/tester.tcl
    20     20   
    21     21   # Do not use a codec for tests in this file, as the database file is
    22     22   # manipulated directly using tcl scripts (using the [hexio_write] command).
    23     23   #
    24     24   do_not_use_codec
           25  +
           26  +# These tests deal with corrupt database files
           27  +#
           28  +database_may_be_corrupt
    25     29   
    26     30   # We must have the page_size pragma for these tests to work.
    27     31   #
    28     32   ifcapable !pager_pragmas||direct_read {
    29     33     finish_test
    30     34     return
    31     35   }

Changes to test/corrupt4.test.

    18     18   set testdir [file dirname $argv0]
    19     19   source $testdir/tester.tcl
    20     20   
    21     21   # Do not use a codec for tests in this file, as the database file is
    22     22   # manipulated directly using tcl scripts (using the [hexio_write] command).
    23     23   #
    24     24   do_not_use_codec
           25  +
           26  +# These tests deal with corrupt database files
           27  +#
           28  +database_may_be_corrupt
    25     29   
    26     30   # We must have the page_size pragma for these tests to work.
    27     31   #
    28     32   ifcapable !pager_pragmas {
    29     33     finish_test
    30     34     return
    31     35   }

Changes to test/corrupt5.test.

    14     14   # segfault if it sees a corrupt database file.  Checks for 
    15     15   # malformed schema.
    16     16   #
    17     17   # $Id: corrupt5.test,v 1.3 2009/06/04 02:47:04 shane Exp $
    18     18   
    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
           21  +
           22  +# These tests deal with corrupt database files
           23  +#
           24  +database_may_be_corrupt
    21     25   
    22     26   # We must have the page_size pragma for these tests to work.
    23     27   #
    24     28   ifcapable !pager_pragmas {
    25     29     finish_test
    26     30     return
    27     31   }

Changes to test/corrupt6.test.

    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Do not use a codec for tests in this file, as the database file is
    23     23   # manipulated directly using tcl scripts (using the [hexio_write] command).
    24     24   #
    25     25   do_not_use_codec
           26  +
           27  +# These tests deal with corrupt database files
           28  +#
           29  +database_may_be_corrupt
    26     30   
    27     31   # We must have the page_size pragma for these tests to work.
    28     32   #
    29     33   ifcapable !pager_pragmas {
    30     34     finish_test
    31     35     return
    32     36   }

Changes to test/corrupt7.test.

    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Do not use a codec for tests in this file, as the database file is
    23     23   # manipulated directly using tcl scripts (using the [hexio_write] command).
    24     24   #
    25     25   do_not_use_codec
           26  +
           27  +# These tests deal with corrupt database files
           28  +#
           29  +database_may_be_corrupt
    26     30   
    27     31   # We must have the page_size pragma for these tests to work.
    28     32   #
    29     33   ifcapable !pager_pragmas {
    30     34     finish_test
    31     35     return
    32     36   }

Changes to test/corrupt8.test.

    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Do not use a codec for tests in this file, as the database file is
    23     23   # manipulated directly using tcl scripts (using the [hexio_write] command).
    24     24   #
    25     25   do_not_use_codec
           26  +
           27  +# These tests deal with corrupt database files
           28  +#
           29  +database_may_be_corrupt
    26     30   
    27     31   # We must have the page_size pragma for these tests to work.
    28     32   #
    29     33   ifcapable !pager_pragmas||!autovacuum {
    30     34     finish_test
    31     35     return
    32     36   }

Changes to test/corrupt9.test.

    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Do not use a codec for tests in this file, as the database file is
    23     23   # manipulated directly using tcl scripts (using the [hexio_write] command).
    24     24   #
    25     25   do_not_use_codec
           26  +
           27  +# These tests deal with corrupt database files
           28  +#
           29  +database_may_be_corrupt
    26     30   
    27     31   # We must have the page_size pragma for these tests to work.
    28     32   #
    29     33   ifcapable !pager_pragmas {
    30     34     finish_test
    31     35     return
    32     36   }

Changes to test/corruptA.test.

    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Do not use a codec for tests in this file, as the database file is
    23     23   # manipulated directly using tcl scripts (using the [hexio_write] command).
    24     24   #
    25     25   do_not_use_codec
           26  +
           27  +# These tests deal with corrupt database files
           28  +#
           29  +database_may_be_corrupt
    26     30   
    27     31   
    28     32   # Create a database to work with.
    29     33   #
    30     34   do_test corruptA-1.1 {
    31     35     execsql {
    32     36       CREATE TABLE t1(x);

Changes to test/corruptB.test.

    25     25   set testdir [file dirname $argv0]
    26     26   source $testdir/tester.tcl
    27     27   
    28     28   # Do not use a codec for tests in this file, as the database file is
    29     29   # manipulated directly using tcl scripts (using the [hexio_write] command).
    30     30   #
    31     31   do_not_use_codec
           32  +
           33  +# These tests deal with corrupt database files
           34  +#
           35  +database_may_be_corrupt
    32     36   
    33     37   
    34     38   do_test corruptB-1.1 {
    35     39     execsql {
    36     40       PRAGMA auto_vacuum = 1;
    37     41       CREATE TABLE t1(x);
    38     42       INSERT INTO t1 VALUES(randomblob(200));

Changes to test/corruptC.test.

    22     22   set testdir [file dirname $argv0]
    23     23   source $testdir/tester.tcl
    24     24   
    25     25   # Do not use a codec for tests in this file, as the database file is
    26     26   # manipulated directly using tcl scripts (using the [hexio_write] command).
    27     27   #
    28     28   do_not_use_codec
           29  +
           30  +# These tests deal with corrupt database files
           31  +#
           32  +database_may_be_corrupt
    29     33   
    30     34   # Construct a compact, dense database for testing.
    31     35   #
    32     36   do_test corruptC-1.1 {
    33     37     execsql {
    34     38       PRAGMA auto_vacuum = 0;
    35     39       PRAGMA legacy_file_format=1;

Changes to test/corruptD.test.

    14     14   set testdir [file dirname $argv0]
    15     15   source $testdir/tester.tcl
    16     16   
    17     17   # Do not use a codec for tests in this file, as the database file is
    18     18   # manipulated directly using tcl scripts (using the [hexio_write] command).
    19     19   #
    20     20   do_not_use_codec
           21  +
           22  +# These tests deal with corrupt database files
           23  +#
           24  +database_may_be_corrupt
    21     25   
    22     26   #--------------------------------------------------------------------------
    23     27   # OVERVIEW
    24     28   #
    25     29   #   This test file attempts to verify that SQLite does not read past the 
    26     30   #   end of any in-memory buffers as a result of corrupted database page 
    27     31   #   images. Usually this happens because a field within a database page

Changes to test/corruptE.test.

    19     19   set testdir [file dirname $argv0]
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   # Do not use a codec for tests in this file, as the database file is
    23     23   # manipulated directly using tcl scripts (using the [hexio_write] command).
    24     24   #
    25     25   do_not_use_codec
           26  +
           27  +# These tests deal with corrupt database files
           28  +#
           29  +database_may_be_corrupt
    26     30   
    27     31   # Do not run the tests in this file if ENABLE_OVERSIZE_CELL_CHECK is on.
    28     32   #
    29     33   ifcapable oversize_cell_check {
    30     34     finish_test
    31     35     return
    32     36   }

Changes to test/corruptF.test.

    14     14   source $testdir/tester.tcl
    15     15   set testprefix corruptF
    16     16   
    17     17   # Do not use a codec for tests in this file, as the database file is
    18     18   # manipulated directly using tcl scripts (using the [hexio_write] command).
    19     19   #
    20     20   do_not_use_codec
           21  +
           22  +# These tests deal with corrupt database files
           23  +#
           24  +database_may_be_corrupt
    21     25   
    22     26   proc str {i} { format %08d $i }
    23     27   
    24     28   # Create a 6 page database containing a single table - t1. Table t1 
    25     29   # consists of page 2 (the root page) and pages 5 and 6 (leaf pages). 
    26     30   # Database pages 3 and 4 are on the free list.
    27     31   #

Changes to test/corruptG.test.

    14     14   source $testdir/tester.tcl
    15     15   set testprefix corruptG
    16     16   
    17     17   # Do not use a codec for tests in this file, as the database file is
    18     18   # manipulated directly using tcl scripts (using the [hexio_write] command).
    19     19   #
    20     20   do_not_use_codec
           21  +
           22  +# These tests deal with corrupt database files
           23  +#
           24  +database_may_be_corrupt
    21     25   
    22     26   # Create a simple database with a single entry.  Then corrupt the
    23     27   # header-size varint on the index payload so that it maps into a
    24     28   # negative number.  Try to use the database.
    25     29   #
    26     30   
    27     31   do_execsql_test 1.1 {

Changes to test/tester.tcl.

  1881   1881   
  1882   1882   # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
  1883   1883   # to non-zero, then set the global variable $AUTOVACUUM to 1.
  1884   1884   set AUTOVACUUM $sqlite_options(default_autovacuum)
  1885   1885   
  1886   1886   # Make sure the FTS enhanced query syntax is disabled.
  1887   1887   set sqlite_fts3_enable_parentheses 0
         1888  +
         1889  +# During testing, assume that all database files are well-formed.  The
         1890  +# few test cases that deliberately corrupt database files should rescind 
         1891  +# this setting by invoking "database_can_be_corrupt"
         1892  +#
         1893  +database_never_corrupt
  1888   1894   
  1889   1895   source $testdir/thread_common.tcl
  1890   1896   source $testdir/malloc_common.tcl