gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/fuzz3.test (about)

     1  # 2007 May 10
     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 focus
    12  # of this file is checking the libraries response to subtly corrupting
    13  # the database file by changing the values of pseudo-randomly selected
    14  # bytes.
    15  #
    16  # $Id: fuzz3.test,v 1.3 2009/01/05 17:19:03 drh Exp $
    17  
    18  set testdir [file dirname $argv0]
    19  source $testdir/tester.tcl
    20  
    21  # These tests deal with corrupt database files
    22  #
    23  database_may_be_corrupt
    24  test_set_config_pagecache 0 0
    25  
    26  
    27  expr srand(123)
    28  
    29  proc rstring {n} {
    30    set str s
    31    while {[string length $str] < $n} {
    32      append str [expr rand()]
    33    }
    34    return [string range $str 0 $n]
    35  }
    36  
    37  # Return a randomly generated SQL literal.
    38  #
    39  proc rvalue {} {
    40    switch -- [expr int(rand()*5)] {
    41      0 { # SQL NULL value.
    42        return NULL 
    43      }
    44      1 { # Integer value.
    45        return [expr int(rand()*1024)] 
    46      }
    47      2 { # Real value.
    48        return [expr rand()] 
    49      }
    50      3 { # String value.
    51        set n [expr int(rand()*2500)]
    52        return "'[rstring $n]'"
    53      }
    54      4 { # Blob value.
    55        set n [expr int(rand()*2500)]
    56        return "CAST('[rstring $n]' AS BLOB)"
    57      }
    58    }
    59  }
    60  
    61  proc db_checksum {} {
    62    set    cksum [execsql { SELECT md5sum(a, b, c) FROM t1 }]
    63    append cksum [execsql { SELECT md5sum(d, e, f) FROM t2 }]
    64    set cksum
    65  }
    66  
    67  # Modify a single byte in the file 'test.db' using tcl IO commands. The
    68  # argument value, which must be an integer, determines both the offset of
    69  # the byte that is modified, and the value that it is set to. The lower
    70  # 8 bits of iMod determine the new byte value. The offset of the byte
    71  # modified is the value of ($iMod >> 8).
    72  #
    73  # The return value is the iMod value required to restore the file
    74  # to its original state. The command:
    75  #
    76  #   modify_database [modify_database $x]
    77  #
    78  # leaves the file in the same state as it was in at the start of the
    79  # command (assuming that the file is at least ($x>>8) bytes in size).
    80  #
    81  proc modify_database {iMod} {
    82    set blob [binary format c [expr {$iMod&0xFF}]]
    83    set offset [expr {$iMod>>8}]
    84  
    85    set fd [open test.db r+]
    86    fconfigure $fd -encoding binary -translation binary
    87    seek $fd $offset
    88    set old_blob [read $fd 1]
    89    seek $fd $offset
    90    puts -nonewline $fd $blob
    91    close $fd
    92  
    93    binary scan $old_blob c iOld
    94    return [expr {($offset<<8) + ($iOld&0xFF)}]
    95  }
    96  
    97  proc purge_pcache {} {
    98    ifcapable !memorymanage {
    99      db close
   100      sqlite3 db test.db
   101    } else {
   102      sqlite3_release_memory 10000000
   103    }
   104    if {[lindex [pcache_stats] 1] != 0} {
   105      error "purge_pcache failed: [pcache_stats]"
   106    }
   107  }
   108  
   109  # This block creates a database to work with. 
   110  #
   111  do_test fuzz3-1 {
   112    execsql {
   113      BEGIN;
   114      CREATE TABLE t1(a, b, c);
   115      CREATE TABLE t2(d, e, f);
   116      CREATE INDEX i1 ON t1(a, b, c);
   117      CREATE INDEX i2 ON t2(d, e, f);
   118    }
   119    for {set i 0} {$i < 50} {incr i} {
   120      execsql "INSERT INTO t1 VALUES([rvalue], [rvalue], [rvalue])"
   121      execsql "INSERT INTO t2 VALUES([rvalue], [rvalue], [rvalue])"
   122    }
   123    execsql COMMIT
   124  } {}
   125  
   126  set ::cksum [db_checksum]
   127  do_test fuzz3-2 {
   128    db_checksum
   129  } $::cksum
   130  
   131  for {set ii 0} {$ii < 5000} {incr ii} {
   132    purge_pcache
   133  
   134    # Randomly modify a single byte of the database file somewhere within
   135    # the first 100KB of the file.
   136    set iNew [expr int(rand()*5*1024*256)]
   137    set iOld [modify_database $iNew]
   138  
   139    set iTest 0
   140    foreach sql {
   141      {SELECT * FROM t2 ORDER BY d}      
   142      {SELECT * FROM t1}                 
   143      {SELECT * FROM t2}                 
   144      {SELECT * FROM t1 ORDER BY a}      
   145      {SELECT * FROM t1 WHERE a = (SELECT a FROM t1 WHERE rowid=25)} 
   146      {SELECT * FROM t2 WHERE d = (SELECT d FROM t2 WHERE rowid=1)}  
   147      {SELECT * FROM t2 WHERE d = (SELECT d FROM t2 WHERE rowid=50)} 
   148      {PRAGMA integrity_check}           
   149    } {
   150      do_test fuzz3-$ii.$iNew.[incr iTest] {
   151        foreach {rc msg} [catchsql $sql] {}
   152        if {$rc == 0 
   153         || $msg eq "database or disk is full"
   154         || $msg eq "database disk image is malformed"
   155         || $msg eq "file is not a database"
   156         || [string match "malformed database schema*" $msg]
   157        } {
   158          set msg ok
   159        }
   160        set msg
   161      } {ok}
   162    }
   163  
   164    # Restore the original database file content. Test that the correct 
   165    # checksum is now returned.
   166    #
   167    purge_pcache
   168    modify_database $iOld
   169    do_test fuzz3-$ii.$iNew.[incr iTest] {
   170      db_checksum
   171    } $::cksum
   172  }
   173  
   174  test_restore_config_pagecache
   175  finish_test