blob: 726bc3297bd97349ae007259ee1614d413c5d9d9 [file] [log] [blame]
drhb19a2bc2001-09-16 00:13:26 +00001# 2001 September 15
drhed7c8552001-04-11 14:29:21 +00002#
drhb19a2bc2001-09-16 00:13:26 +00003# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
drhed7c8552001-04-11 14:29:21 +00005#
drhb19a2bc2001-09-16 00:13:26 +00006# 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.
drhed7c8552001-04-11 14:29:21 +00009#
10#***********************************************************************
11# This file attempts to check the library in an out-of-memory situation.
drhc89b91b2005-01-03 01:32:59 +000012# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special
drh6d4abfb2001-10-22 02:58:08 +000013# command (sqlite_malloc_fail N) which causes the N-th malloc to fail. This
drhed7c8552001-04-11 14:29:21 +000014# special feature is used to see what happens in the library if a malloc
15# were to really fail due to an out-of-memory situation.
16#
danielk1977771151b2006-01-17 13:21:40 +000017# $Id: malloc.test,v 1.27 2006/01/17 13:21:40 danielk1977 Exp $
drhed7c8552001-04-11 14:29:21 +000018
19set testdir [file dirname $argv0]
20source $testdir/tester.tcl
21
22# Only run these tests if memory debugging is turned on.
23#
drhb5f70c22004-02-14 01:39:50 +000024if {[info command sqlite_malloc_stat]==""} {
danielk1977261919c2005-12-06 12:52:59 +000025 puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
drhed7c8552001-04-11 14:29:21 +000026 finish_test
27 return
28}
29
danielk19774397de52005-01-12 12:44:03 +000030# Usage: do_malloc_test <test number> <options...>
31#
32# The first argument, <test number>, is an integer used to name the
33# tests executed by this proc. Options are as follows:
34#
35# -tclprep TCL script to run to prepare test.
36# -sqlprep SQL script to run to prepare test.
danielk1977656152c2005-01-12 13:04:54 +000037# -tclbody TCL script to run with malloc failure simulation.
38# -sqlbody TCL script to run with malloc failure simulation.
danielk1977c08d4052005-01-13 13:35:57 +000039# -cleanup TCL script to run after the test.
danielk1977656152c2005-01-12 13:04:54 +000040#
41# This command runs a series of tests to verify SQLite's ability
42# to handle an out-of-memory condition gracefully. It is assumed
43# that if this condition occurs a malloc() call will return a
44# NULL pointer. Linux, for example, doesn't do that by default. See
45# the "BUGS" section of malloc(3).
46#
47# Each iteration of a loop, the TCL commands in any argument passed
48# to the -tclbody switch, followed by the SQL commands in any argument
49# passed to the -sqlbody switch are executed. Each iteration the
50# Nth call to sqliteMalloc() is made to fail, where N is increased
51# each time the loop runs starting from 1. When all commands execute
52# successfully, the loop ends.
danielk19774397de52005-01-12 12:44:03 +000053#
54proc do_malloc_test {tn args} {
danielk1977261919c2005-12-06 12:52:59 +000055 array unset ::mallocopts
danielk19774397de52005-01-12 12:44:03 +000056 array set ::mallocopts $args
57
58 set ::go 1
danielk1977261919c2005-12-06 12:52:59 +000059 for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
danielk19774397de52005-01-12 12:44:03 +000060 do_test malloc-$tn.$::n {
61
danielk1977261919c2005-12-06 12:52:59 +000062 # Remove all traces of database files test.db and test2.db from the files
63 # system. Then open (empty database) "test.db" with the handle [db].
64 #
danielk19774397de52005-01-12 12:44:03 +000065 sqlite_malloc_fail 0
danielk1977771151b2006-01-17 13:21:40 +000066 catch {db close}
danielk19774397de52005-01-12 12:44:03 +000067 catch {file delete -force test.db}
68 catch {file delete -force test.db-journal}
69 catch {file delete -force test2.db}
70 catch {file delete -force test2.db-journal}
danielk1977771151b2006-01-17 13:21:40 +000071 catch {sqlite3 db test.db}
72 set ::DB [sqlite3_connection_pointer db]
danielk19774397de52005-01-12 12:44:03 +000073
danielk1977261919c2005-12-06 12:52:59 +000074 # Execute any -tclprep and -sqlprep scripts.
75 #
danielk19774397de52005-01-12 12:44:03 +000076 if {[info exists ::mallocopts(-tclprep)]} {
77 eval $::mallocopts(-tclprep)
78 }
79 if {[info exists ::mallocopts(-sqlprep)]} {
80 execsql $::mallocopts(-sqlprep)
81 }
82
danielk1977261919c2005-12-06 12:52:59 +000083 # Now set the ${::n}th malloc() to fail and execute the -tclbody and
84 # -sqlbody scripts.
85 #
danielk19774397de52005-01-12 12:44:03 +000086 sqlite_malloc_fail $::n
87 set ::mallocbody {}
88 if {[info exists ::mallocopts(-tclbody)]} {
89 append ::mallocbody "$::mallocopts(-tclbody)\n"
90 }
91 if {[info exists ::mallocopts(-sqlbody)]} {
92 append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
93 }
danielk19774397de52005-01-12 12:44:03 +000094 set v [catch $::mallocbody msg]
95
96 set leftover [lindex [sqlite_malloc_stat] 2]
97 if {$leftover>0} {
98 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
99 set ::go 0
100 set v {1 1}
101 } else {
102 set v2 [expr {$msg=="" || $msg=="out of memory"}]
103 if {!$v2} {puts "\nError message returned: $msg"}
104 lappend v $v2
105 }
106 } {1 1}
danielk1977c08d4052005-01-13 13:35:57 +0000107
108 if {[info exists ::mallocopts(-cleanup)]} {
109 catch $::mallocopts(-cleanup)
110 }
danielk19774397de52005-01-12 12:44:03 +0000111 }
danielk1977aca790a2005-01-13 11:07:52 +0000112 unset ::mallocopts
danielk19774397de52005-01-12 12:44:03 +0000113}
114
danielk1977c08d4052005-01-13 13:35:57 +0000115do_malloc_test 1 -tclprep {
116 db close
117} -tclbody {
118 if {[catch {sqlite3 db test.db}]} {
119 error "out of memory"
120 }
121} -sqlbody {
122 CREATE TABLE t1(
123 a int, b float, c double, d text, e varchar(20),
124 primary key(a,b,c)
125 );
126 CREATE INDEX i1 ON t1(a,b);
127 INSERT INTO t1 VALUES(1,2.3,4.5,'hi','there');
128 INSERT INTO t1 VALUES(6,7.0,0.8,'hello','out yonder');
129 SELECT * FROM t1;
130 SELECT avg(b) FROM t1 GROUP BY a HAVING b>20.0;
131 DELETE FROM t1 WHERE a IN (SELECT min(a) FROM t1);
132 SELECT count(*) FROM t1;
133}
drhd4007282001-04-12 23:21:58 +0000134
danielk1977b5548a82004-06-26 13:51:33 +0000135# Ensure that no file descriptors were leaked.
136do_test malloc-1.X {
137 catch {db close}
138 set sqlite_open_file_count
139} {0}
140
danielk1977c08d4052005-01-13 13:35:57 +0000141do_malloc_test 2 -sqlbody {
drhfc233142005-08-19 01:07:15 +0000142 CREATE TABLE t1(a int, b int default 'abc', c int default 1);
danielk1977c08d4052005-01-13 13:35:57 +0000143 CREATE INDEX i1 ON t1(a,b);
144 INSERT INTO t1 VALUES(1,1,'99 abcdefghijklmnopqrstuvwxyz');
145 INSERT INTO t1 VALUES(2,4,'98 abcdefghijklmnopqrstuvwxyz');
146 INSERT INTO t1 VALUES(3,9,'97 abcdefghijklmnopqrstuvwxyz');
147 INSERT INTO t1 VALUES(4,16,'96 abcdefghijklmnopqrstuvwxyz');
148 INSERT INTO t1 VALUES(5,25,'95 abcdefghijklmnopqrstuvwxyz');
149 INSERT INTO t1 VALUES(6,36,'94 abcdefghijklmnopqrstuvwxyz');
150 SELECT 'stuff', count(*) as 'other stuff', max(a+10) FROM t1;
151 UPDATE t1 SET b=b||b||b||b;
152 UPDATE t1 SET b=a WHERE a in (10,12,22);
153 INSERT INTO t1(c,b,a) VALUES(20,10,5);
154 INSERT INTO t1 SELECT * FROM t1
155 WHERE a IN (SELECT a FROM t1 WHERE a<10);
156 DELETE FROM t1 WHERE a>=10;
157 DROP INDEX i1;
158 DELETE FROM t1;
159}
drh6d4abfb2001-10-22 02:58:08 +0000160
danielk1977b5548a82004-06-26 13:51:33 +0000161# Ensure that no file descriptors were leaked.
162do_test malloc-2.X {
163 catch {db close}
164 set sqlite_open_file_count
165} {0}
166
danielk1977c08d4052005-01-13 13:35:57 +0000167do_malloc_test 3 -sqlbody {
168 BEGIN TRANSACTION;
169 CREATE TABLE t1(a int, b int, c int);
170 CREATE INDEX i1 ON t1(a,b);
171 INSERT INTO t1 VALUES(1,1,99);
172 INSERT INTO t1 VALUES(2,4,98);
173 INSERT INTO t1 VALUES(3,9,97);
174 INSERT INTO t1 VALUES(4,16,96);
175 INSERT INTO t1 VALUES(5,25,95);
176 INSERT INTO t1 VALUES(6,36,94);
177 INSERT INTO t1(c,b,a) VALUES(20,10,5);
178 DELETE FROM t1 WHERE a>=10;
179 DROP INDEX i1;
180 DELETE FROM t1;
181 ROLLBACK;
182}
183
danielk1977b5548a82004-06-26 13:51:33 +0000184
185# Ensure that no file descriptors were leaked.
186do_test malloc-3.X {
187 catch {db close}
188 set sqlite_open_file_count
189} {0}
190
danielk1977c08d4052005-01-13 13:35:57 +0000191do_malloc_test 4 -sqlbody {
192 BEGIN TRANSACTION;
193 CREATE TABLE t1(a int, b int, c int);
194 CREATE INDEX i1 ON t1(a,b);
195 INSERT INTO t1 VALUES(1,1,99);
196 INSERT INTO t1 VALUES(2,4,98);
197 INSERT INTO t1 VALUES(3,9,97);
198 INSERT INTO t1 VALUES(4,16,96);
199 INSERT INTO t1 VALUES(5,25,95);
200 INSERT INTO t1 VALUES(6,36,94);
201 UPDATE t1 SET b=a WHERE a in (10,12,22);
202 INSERT INTO t1 SELECT * FROM t1
203 WHERE a IN (SELECT a FROM t1 WHERE a<10);
204 DROP INDEX i1;
205 DELETE FROM t1;
206 COMMIT;
207}
danielk1977b5548a82004-06-26 13:51:33 +0000208
209# Ensure that no file descriptors were leaked.
210do_test malloc-4.X {
211 catch {db close}
212 set sqlite_open_file_count
213} {0}
214
danielk1977c08d4052005-01-13 13:35:57 +0000215do_malloc_test 5 -sqlbody {
216 BEGIN TRANSACTION;
217 CREATE TABLE t1(a,b);
218 CREATE TABLE t2(x,y);
219 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
220 INSERT INTO t2(x,y) VALUES(new.rowid,1);
221 END;
222 INSERT INTO t1(a,b) VALUES(2,3);
223 COMMIT;
224}
danielk1977b5548a82004-06-26 13:51:33 +0000225
226# Ensure that no file descriptors were leaked.
227do_test malloc-5.X {
228 catch {db close}
229 set sqlite_open_file_count
230} {0}
231
danielk1977c08d4052005-01-13 13:35:57 +0000232do_malloc_test 6 -sqlprep {
233 BEGIN TRANSACTION;
234 CREATE TABLE t1(a);
235 INSERT INTO t1 VALUES(1);
236 INSERT INTO t1 SELECT a*2 FROM t1;
237 INSERT INTO t1 SELECT a*2 FROM t1;
238 INSERT INTO t1 SELECT a*2 FROM t1;
239 INSERT INTO t1 SELECT a*2 FROM t1;
240 INSERT INTO t1 SELECT a*2 FROM t1;
241 INSERT INTO t1 SELECT a*2 FROM t1;
242 INSERT INTO t1 SELECT a*2 FROM t1;
243 INSERT INTO t1 SELECT a*2 FROM t1;
244 INSERT INTO t1 SELECT a*2 FROM t1;
245 INSERT INTO t1 SELECT a*2 FROM t1;
246 DELETE FROM t1 where rowid%5 = 0;
247 COMMIT;
248} -sqlbody {
249 VACUUM;
250}
danielk197796fb0dd2004-06-30 09:49:22 +0000251
danielk1977c08d4052005-01-13 13:35:57 +0000252do_malloc_test 7 -sqlprep {
253 CREATE TABLE t1(a, b);
254 INSERT INTO t1 VALUES(1, 2);
255 INSERT INTO t1 VALUES(3, 4);
256 INSERT INTO t1 VALUES(5, 6);
257 INSERT INTO t1 VALUES(7, randstr(1200,1200));
258} -sqlbody {
259 SELECT min(a) FROM t1 WHERE a<6 GROUP BY b;
260 SELECT a FROM t1 WHERE a<6 ORDER BY a;
261 SELECT b FROM t1 WHERE a>6;
262}
danielk197701427a62005-01-11 13:02:33 +0000263
danielk1977b5402fb2005-01-12 07:15:04 +0000264# This block is designed to test that some malloc failures that may
265# occur in vdbeapi.c. Specifically, if a malloc failure that occurs
266# when converting UTF-16 text to integers and real numbers is handled
267# correctly.
268#
danielk19778b60e0f2005-01-12 09:10:39 +0000269# This is done by retrieving a string from the database engine and
270# manipulating it using the sqlite3_column_*** APIs. This doesn't
271# actually return an error to the user when a malloc() fails.. That
272# could be viewed as a bug.
273#
274# These tests only run if UTF-16 support is compiled in.
danielk1977b5402fb2005-01-12 07:15:04 +0000275#
danielk1977c08d4052005-01-13 13:35:57 +0000276if {$::sqlite_options(utf16)} {
277 do_malloc_test 8 -tclprep {
278 set sql "SELECT '[string repeat abc 20]', '[string repeat def 20]', ?"
279 set ::STMT [sqlite3_prepare $::DB $sql -1 X]
280 sqlite3_step $::STMT
281 if { $::tcl_platform(byteOrder)=="littleEndian" } {
282 set ::bomstr "\xFF\xFE"
283 } else {
284 set ::bomstr "\xFE\xFF"
285 }
286 append ::bomstr [encoding convertto unicode "123456789_123456789_12345678"]
287 } -tclbody {
288 sqlite3_column_text16 $::STMT 0
289 sqlite3_column_int $::STMT 0
290 sqlite3_column_text16 $::STMT 1
291 sqlite3_column_double $::STMT 1
292 sqlite3_reset $::STMT
293 sqlite3_bind_text16 $::STMT 1 $::bomstr 60
294 catch {sqlite3_finalize $::STMT}
295 if {[lindex [sqlite_malloc_stat] 2]<=0} {
296 error "out of memory"
297 }
298 } -cleanup {
299 sqlite3_finalize $::STMT
300 }
danielk1977b5402fb2005-01-12 07:15:04 +0000301}
302
danielk19778b60e0f2005-01-12 09:10:39 +0000303# This block tests that malloc() failures that occur whilst commiting
304# a multi-file transaction are handled correctly.
305#
danielk19774397de52005-01-12 12:44:03 +0000306do_malloc_test 9 -sqlprep {
307 ATTACH 'test2.db' as test2;
308 CREATE TABLE abc1(a, b, c);
309 CREATE TABLE test2.abc2(a, b, c);
310} -sqlbody {
311 BEGIN;
312 INSERT INTO abc1 VALUES(1, 2, 3);
313 INSERT INTO abc2 VALUES(1, 2, 3);
314 COMMIT;
danielk19778b60e0f2005-01-12 09:10:39 +0000315}
316
danielk19774397de52005-01-12 12:44:03 +0000317# This block tests malloc() failures that occur while opening a
318# connection to a database.
319do_malloc_test 10 -sqlprep {
320 CREATE TABLE abc(a, b, c);
321} -tclbody {
danielk1977771151b2006-01-17 13:21:40 +0000322 sqlite3 db2 test.db
danielk19774397de52005-01-12 12:44:03 +0000323 db2 eval {SELECT * FROM sqlite_master}
324 db2 close
325}
326
327# This block tests malloc() failures that occur within calls to
328# sqlite3_create_function().
329do_malloc_test 11 -tclbody {
danielk19772c336542005-01-13 02:14:23 +0000330 set rc [sqlite3_create_function $::DB]
331 if {[string match $rc SQLITE_NOMEM]} {
danielk19774397de52005-01-12 12:44:03 +0000332 error "out of memory"
333 }
334}
335
336do_malloc_test 12 -tclbody {
337 set sql16 [encoding convertto unicode "SELECT * FROM sqlite_master"]
338 append sql16 "\00\00"
339 set ::STMT [sqlite3_prepare16 $::DB $sql16 -1 DUMMY]
340 sqlite3_finalize $::STMT
341}
danielk19778b60e0f2005-01-12 09:10:39 +0000342
danielk1977aca790a2005-01-13 11:07:52 +0000343# Test malloc errors when replaying two hot journals from a 2-file
drh66560ad2006-01-06 14:32:19 +0000344# transaction.
345ifcapable crashtest {
danielk1977aca790a2005-01-13 11:07:52 +0000346 do_malloc_test 13 -tclprep {
347 set rc [crashsql 1 test2.db {
348 ATTACH 'test2.db' as aux;
349 PRAGMA cache_size = 10;
350 BEGIN;
351 CREATE TABLE aux.t2(a, b, c);
352 CREATE TABLE t1(a, b, c);
353 COMMIT;
354 }]
355 if {$rc!="1 {child process exited abnormally}"} {
356 error "Wrong error message: $rc"
357 }
358 } -sqlbody {
359 ATTACH 'test2.db' as aux;
360 SELECT * FROM t1;
361 SELECT * FROM t2;
362 }
363}
364
danielk197776b047d2005-01-19 03:52:54 +0000365if {$tcl_platform(platform)!="windows"} {
danielk1977aca790a2005-01-13 11:07:52 +0000366do_malloc_test 14 -tclprep {
367 catch {db close}
368 sqlite3 db2 test2.db
369 db2 eval {
370 PRAGMA synchronous = 0;
371 CREATE TABLE t1(a, b);
372 INSERT INTO t1 VALUES(1, 2);
373 BEGIN;
374 INSERT INTO t1 VALUES(3, 4);
375 }
danielk197732554c12005-01-22 03:39:39 +0000376 copy_file test2.db test.db
377 copy_file test2.db-journal test.db-journal
danielk1977aca790a2005-01-13 11:07:52 +0000378 db2 close
379} -tclbody {
380 sqlite3 db test.db
381 db eval {
382 SELECT * FROM t1;
383 }
384}
danielk197776b047d2005-01-19 03:52:54 +0000385}
danielk1977aca790a2005-01-13 11:07:52 +0000386
danielk197796fb0dd2004-06-30 09:49:22 +0000387# Ensure that no file descriptors were leaked.
danielk1977b5402fb2005-01-12 07:15:04 +0000388do_test malloc-99.X {
danielk197796fb0dd2004-06-30 09:49:22 +0000389 catch {db close}
390 set sqlite_open_file_count
391} {0}
392
drhed7c8552001-04-11 14:29:21 +0000393sqlite_malloc_fail 0
394finish_test