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