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