blob: 507b90727e09d40b903edcc22b5a77dd1dc65182 [file] [log] [blame]
drhcf1be452007-05-12 12:08:51 +00001# 2007 April 30
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 contains additional out-of-memory checks (see malloc.tcl).
12#
13# $Id: mallocA.test,v 1.1 2007/05/12 12:08:51 drh Exp $
14
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17
18# Only run these tests if memory debugging is turned on.
19#
20if {[info command sqlite_malloc_stat]==""} {
21 puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
22 finish_test
23 return
24}
25
26# Usage: do_malloc_test <test number> <options...>
27#
28# The first argument, <test number>, is an integer used to name the
29# tests executed by this proc. Options are as follows:
30#
31# -tclprep TCL script to run to prepare test.
32# -sqlprep SQL script to run to prepare test.
33# -tclbody TCL script to run with malloc failure simulation.
34# -sqlbody TCL script to run with malloc failure simulation.
35# -cleanup TCL script to run after the test.
36#
37# This command runs a series of tests to verify SQLite's ability
38# to handle an out-of-memory condition gracefully. It is assumed
39# that if this condition occurs a malloc() call will return a
40# NULL pointer. Linux, for example, doesn't do that by default. See
41# the "BUGS" section of malloc(3).
42#
43# Each iteration of a loop, the TCL commands in any argument passed
44# to the -tclbody switch, followed by the SQL commands in any argument
45# passed to the -sqlbody switch are executed. Each iteration the
46# Nth call to sqliteMalloc() is made to fail, where N is increased
47# each time the loop runs starting from 1. When all commands execute
48# successfully, the loop ends.
49#
50proc do_malloc_test {tn args} {
51 array unset ::mallocopts
52 array set ::mallocopts $args
53
54 set ::go 1
55 for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
56 do_test mallocA-$tn.$::n {
57
58 sqlite_malloc_fail 0
59 catch {db close}
60 catch {file delete -force test.db test.db-journal}
61 catch {file copy test.db.bu test.db}
62 sqlite3 db test.db
63 set ::DB [sqlite3_connection_pointer db]
64
65 # Execute any -tclprep and -sqlprep scripts.
66 #
67 if {[info exists ::mallocopts(-tclprep)]} {
68 eval $::mallocopts(-tclprep)
69 }
70 if {[info exists ::mallocopts(-sqlprep)]} {
71 execsql $::mallocopts(-sqlprep)
72 }
73
74 # Now set the ${::n}th malloc() to fail and execute the -tclbody and
75 # -sqlbody scripts.
76 #
77 sqlite_malloc_fail $::n
78 set ::mallocbody {}
79 if {[info exists ::mallocopts(-tclbody)]} {
80 append ::mallocbody "$::mallocopts(-tclbody)\n"
81 }
82 if {[info exists ::mallocopts(-sqlbody)]} {
83 append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
84 }
85 set v [catch $::mallocbody msg]
86
87 # If the test fails (if $v!=0) and the database connection actually
88 # exists, make sure the failure code is SQLITE_NOMEM.
89 if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)]
90 && [db errorcode]!=7} {
91 set v 999
92 }
93
94 set leftover [lindex [sqlite_malloc_stat] 2]
95 if {$leftover>0} {
96 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
97 set ::go 0
98 if {$v} {
99 puts "\nError message returned: $msg"
100 } else {
101 set v {1 1}
102 }
103 } else {
104 set v2 [expr {$msg=="" || [regexp {out of memory} $msg]}]
105 if {!$v2} {puts "\nError message returned: $msg"}
106 lappend v $v2
107 }
108 } {1 1}
109
110 if {[info exists ::mallocopts(-cleanup)]} {
111 catch [list uplevel #0 $::mallocopts(-cleanup)] msg
112 }
113 }
114 unset ::mallocopts
115}
116
117# Construct a test database
118#
119file delete -force test.db.bu
120db eval {
121 CREATE TABLE t1(a,b,c);
122 INSERT INTO t1 VALUES(1,2,3);
123 INSERT INTO t1 VALUES(1,2,4);
124 INSERT INTO t1 VALUES(2,3,4);
125 CREATE INDEX t1i1 ON t1(a);
126 CREATE INDEX t1i2 ON t1(b,c);
127 CREATE TABLE t2(x,y,z);
128}
129db close
130file copy test.db test.db.bu
131sqlite3 db test.db
132
133
134do_malloc_test 1 -sqlbody {
135 ANALYZE
136}
137
138# Ensure that no file descriptors were leaked.
139do_test malloc-99.X {
140 catch {db close}
141 set sqlite_open_file_count
142} {0}
143
144file delete -force test.db.bu
145sqlite_malloc_fail 0
146finish_test