1
0

fuzz3.test 4.4 KB

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