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