blob: 33e2b630898b795d0cb48a3bebc177a7339849d9 [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#
danielk19772c336542005-01-13 02:14:23 +000017# $Id: malloc.test,v 1.18 2005/01/13 02:14:25 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]==""} {
drhc89b91b2005-01-03 01:32:59 +000025 puts "Skipping malloc tests: not compiled with -DSQLITE_DEBUG..."
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.
39#
40# This command runs a series of tests to verify SQLite's ability
41# to handle an out-of-memory condition gracefully. It is assumed
42# that if this condition occurs a malloc() call will return a
43# NULL pointer. Linux, for example, doesn't do that by default. See
44# the "BUGS" section of malloc(3).
45#
46# Each iteration of a loop, the TCL commands in any argument passed
47# to the -tclbody switch, followed by the SQL commands in any argument
48# passed to the -sqlbody switch are executed. Each iteration the
49# Nth call to sqliteMalloc() is made to fail, where N is increased
50# each time the loop runs starting from 1. When all commands execute
51# successfully, the loop ends.
danielk19774397de52005-01-12 12:44:03 +000052#
53proc do_malloc_test {tn args} {
54 array set ::mallocopts $args
55
56 set ::go 1
57 for {set ::n 1} {$::go} {incr ::n} {
58
59 do_test malloc-$tn.$::n {
60
61 sqlite_malloc_fail 0
62 catch {db close}
63 catch {file delete -force test.db}
64 catch {file delete -force test.db-journal}
65 catch {file delete -force test2.db}
66 catch {file delete -force test2.db-journal}
67 set ::DB [sqlite3 db test.db]
68
69 if {[info exists ::mallocopts(-tclprep)]} {
70 eval $::mallocopts(-tclprep)
71 }
72 if {[info exists ::mallocopts(-sqlprep)]} {
73 execsql $::mallocopts(-sqlprep)
74 }
75
76 sqlite_malloc_fail $::n
77 set ::mallocbody {}
78 if {[info exists ::mallocopts(-tclbody)]} {
79 append ::mallocbody "$::mallocopts(-tclbody)\n"
80 }
81 if {[info exists ::mallocopts(-sqlbody)]} {
82 append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
83 }
84
85 set v [catch $::mallocbody msg]
86
87 set leftover [lindex [sqlite_malloc_stat] 2]
88 if {$leftover>0} {
89 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
90 set ::go 0
91 set v {1 1}
92 } else {
93 set v2 [expr {$msg=="" || $msg=="out of memory"}]
94 if {!$v2} {puts "\nError message returned: $msg"}
95 lappend v $v2
96 }
97 } {1 1}
98 }
99}
100
drhed7c8552001-04-11 14:29:21 +0000101for {set go 1; set i 1} {$go} {incr i} {
102 do_test malloc-1.$i {
103 sqlite_malloc_fail 0
drh6d4abfb2001-10-22 02:58:08 +0000104 catch {db close}
105 catch {file delete -force test.db}
106 catch {file delete -force test.db-journal}
drh46934232004-11-20 19:18:00 +0000107 sqlite_malloc_fail $i [expr {$i%4}]
drhef4ac8f2004-06-19 00:16:31 +0000108 set v [catch {sqlite3 db test.db} msg]
drh6d4abfb2001-10-22 02:58:08 +0000109 if {$v} {
110 set msg ""
111 } else {
112 set v [catch {execsql {
113 CREATE TABLE t1(
114 a int, b float, c double, d text, e varchar(20),
115 primary key(a,b,c)
116 );
117 CREATE INDEX i1 ON t1(a,b);
118 INSERT INTO t1 VALUES(1,2.3,4.5,'hi','there');
119 INSERT INTO t1 VALUES(6,7.0,0.8,'hello','out yonder');
120 SELECT * FROM t1;
121 SELECT avg(b) FROM t1 GROUP BY a HAVING b>20.0;
122 DELETE FROM t1 WHERE a IN (SELECT min(a) FROM t1);
123 SELECT count(*) FROM t1;
124 }} msg]
125 }
126 set leftover [lindex [sqlite_malloc_stat] 2]
127 if {$leftover>0} {
128 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
drhed7c8552001-04-11 14:29:21 +0000129 set ::go 0
130 set v {1 1}
131 } else {
drh6d4abfb2001-10-22 02:58:08 +0000132 set v2 [expr {$msg=="" || $msg=="out of memory"}]
133 if {!$v2} {puts "\nError message returned: $msg"}
134 lappend v $v2
drhed7c8552001-04-11 14:29:21 +0000135 }
136 } {1 1}
137}
drhd4007282001-04-12 23:21:58 +0000138
danielk1977b5548a82004-06-26 13:51:33 +0000139# Ensure that no file descriptors were leaked.
140do_test malloc-1.X {
141 catch {db close}
142 set sqlite_open_file_count
143} {0}
144
drhd4007282001-04-12 23:21:58 +0000145set fd [open ./data.tmp w]
drh6d4abfb2001-10-22 02:58:08 +0000146for {set i 1} {$i<=20} {incr i} {
drh5f3b4ab2004-05-27 17:22:54 +0000147 puts $fd "$i\t[expr {$i*$i}]\t[expr {100-$i}] abcdefghijklmnopqrstuvwxyz"
drhd4007282001-04-12 23:21:58 +0000148}
149close $fd
150
151for {set go 1; set i 1} {$go} {incr i} {
152 do_test malloc-2.$i {
153 sqlite_malloc_fail 0
drh6d4abfb2001-10-22 02:58:08 +0000154 catch {db close}
155 catch {file delete -force test.db}
156 catch {file delete -force test.db-journal}
drhd4007282001-04-12 23:21:58 +0000157 sqlite_malloc_fail $i
drhef4ac8f2004-06-19 00:16:31 +0000158 set v [catch {sqlite3 db test.db} msg]
drh6d4abfb2001-10-22 02:58:08 +0000159 if {$v} {
160 set msg ""
161 } else {
162 set v [catch {execsql {
163 CREATE TABLE t1(a int, b int, c int);
164 CREATE INDEX i1 ON t1(a,b);
drh5f3b4ab2004-05-27 17:22:54 +0000165 INSERT INTO t1 VALUES(1,1,'99 abcdefghijklmnopqrstuvwxyz');
166 INSERT INTO t1 VALUES(2,4,'98 abcdefghijklmnopqrstuvwxyz');
167 INSERT INTO t1 VALUES(3,9,'97 abcdefghijklmnopqrstuvwxyz');
168 INSERT INTO t1 VALUES(4,16,'96 abcdefghijklmnopqrstuvwxyz');
169 INSERT INTO t1 VALUES(5,25,'95 abcdefghijklmnopqrstuvwxyz');
170 INSERT INTO t1 VALUES(6,36,'94 abcdefghijklmnopqrstuvwxyz');
drh6d4abfb2001-10-22 02:58:08 +0000171 SELECT 'stuff', count(*) as 'other stuff', max(a+10) FROM t1;
172 UPDATE t1 SET b=b||b||b||b;
173 UPDATE t1 SET b=a WHERE a in (10,12,22);
174 INSERT INTO t1(c,b,a) VALUES(20,10,5);
175 INSERT INTO t1 SELECT * FROM t1
176 WHERE a IN (SELECT a FROM t1 WHERE a<10);
177 DELETE FROM t1 WHERE a>=10;
178 DROP INDEX i1;
179 DELETE FROM t1;
180 }} msg]
181 }
182 set leftover [lindex [sqlite_malloc_stat] 2]
183 if {$leftover>0} {
184 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
drhd4007282001-04-12 23:21:58 +0000185 set ::go 0
186 set v {1 1}
187 } else {
drh6d4abfb2001-10-22 02:58:08 +0000188 set v2 [expr {$msg=="" || $msg=="out of memory"}]
189 if {!$v2} {puts "\nError message returned: $msg"}
190 lappend v $v2
191 }
192 } {1 1}
193}
194
danielk1977b5548a82004-06-26 13:51:33 +0000195# Ensure that no file descriptors were leaked.
196do_test malloc-2.X {
197 catch {db close}
198 set sqlite_open_file_count
199} {0}
200
drh6d4abfb2001-10-22 02:58:08 +0000201for {set go 1; set i 1} {$go} {incr i} {
202 do_test malloc-3.$i {
203 sqlite_malloc_fail 0
204 catch {db close}
205 catch {file delete -force test.db}
206 catch {file delete -force test.db-journal}
207 sqlite_malloc_fail $i
drhef4ac8f2004-06-19 00:16:31 +0000208 set v [catch {sqlite3 db test.db} msg]
drh6d4abfb2001-10-22 02:58:08 +0000209 if {$v} {
210 set msg ""
211 } else {
212 set v [catch {execsql {
213 BEGIN TRANSACTION;
214 CREATE TABLE t1(a int, b int, c int);
215 CREATE INDEX i1 ON t1(a,b);
drh5f3b4ab2004-05-27 17:22:54 +0000216 INSERT INTO t1 VALUES(1,1,99);
217 INSERT INTO t1 VALUES(2,4,98);
218 INSERT INTO t1 VALUES(3,9,97);
219 INSERT INTO t1 VALUES(4,16,96);
220 INSERT INTO t1 VALUES(5,25,95);
221 INSERT INTO t1 VALUES(6,36,94);
drh6d4abfb2001-10-22 02:58:08 +0000222 INSERT INTO t1(c,b,a) VALUES(20,10,5);
223 DELETE FROM t1 WHERE a>=10;
224 DROP INDEX i1;
225 DELETE FROM t1;
226 ROLLBACK;
227 }} msg]
228 }
229 set leftover [lindex [sqlite_malloc_stat] 2]
230 if {$leftover>0} {
231 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
232 set ::go 0
233 set v {1 1}
234 } else {
235 set v2 [expr {$msg=="" || $msg=="out of memory"}]
236 if {!$v2} {puts "\nError message returned: $msg"}
237 lappend v $v2
238 }
239 } {1 1}
240}
danielk1977b5548a82004-06-26 13:51:33 +0000241
242# Ensure that no file descriptors were leaked.
243do_test malloc-3.X {
244 catch {db close}
245 set sqlite_open_file_count
246} {0}
247
drh6d4abfb2001-10-22 02:58:08 +0000248for {set go 1; set i 1} {$go} {incr i} {
249 do_test malloc-4.$i {
250 sqlite_malloc_fail 0
251 catch {db close}
252 catch {file delete -force test.db}
253 catch {file delete -force test.db-journal}
254 sqlite_malloc_fail $i
drhef4ac8f2004-06-19 00:16:31 +0000255 set v [catch {sqlite3 db test.db} msg]
drh6d4abfb2001-10-22 02:58:08 +0000256 if {$v} {
257 set msg ""
258 } else {
259 set v [catch {execsql {
260 BEGIN TRANSACTION;
261 CREATE TABLE t1(a int, b int, c int);
262 CREATE INDEX i1 ON t1(a,b);
drh5f3b4ab2004-05-27 17:22:54 +0000263 INSERT INTO t1 VALUES(1,1,99);
264 INSERT INTO t1 VALUES(2,4,98);
265 INSERT INTO t1 VALUES(3,9,97);
266 INSERT INTO t1 VALUES(4,16,96);
267 INSERT INTO t1 VALUES(5,25,95);
268 INSERT INTO t1 VALUES(6,36,94);
drh6d4abfb2001-10-22 02:58:08 +0000269 UPDATE t1 SET b=a WHERE a in (10,12,22);
270 INSERT INTO t1 SELECT * FROM t1
271 WHERE a IN (SELECT a FROM t1 WHERE a<10);
272 DROP INDEX i1;
273 DELETE FROM t1;
274 COMMIT;
275 }} msg]
276 }
277 set leftover [lindex [sqlite_malloc_stat] 2]
278 if {$leftover>0} {
279 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
280 set ::go 0
281 set v {1 1}
282 } else {
283 set v2 [expr {$msg=="" || $msg=="out of memory"}]
284 if {!$v2} {puts "\nError message returned: $msg"}
285 lappend v $v2
drhd4007282001-04-12 23:21:58 +0000286 }
287 } {1 1}
288}
danielk1977b5548a82004-06-26 13:51:33 +0000289
290# Ensure that no file descriptors were leaked.
291do_test malloc-4.X {
292 catch {db close}
293 set sqlite_open_file_count
294} {0}
295
drhe4697f52002-05-23 02:09:03 +0000296for {set go 1; set i 1} {$go} {incr i} {
297 do_test malloc-5.$i {
298 sqlite_malloc_fail 0
299 catch {db close}
300 catch {file delete -force test.db}
301 catch {file delete -force test.db-journal}
302 sqlite_malloc_fail $i
drhef4ac8f2004-06-19 00:16:31 +0000303 set v [catch {sqlite3 db test.db} msg]
drhe4697f52002-05-23 02:09:03 +0000304 if {$v} {
305 set msg ""
306 } else {
307 set v [catch {execsql {
308 BEGIN TRANSACTION;
309 CREATE TABLE t1(a,b);
310 CREATE TABLE t2(x,y);
311 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
312 INSERT INTO t2(x,y) VALUES(new.rowid,1);
313 END;
314 INSERT INTO t1(a,b) VALUES(2,3);
315 COMMIT;
316 }} msg]
317 }
318 set leftover [lindex [sqlite_malloc_stat] 2]
319 if {$leftover>0} {
320 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
321 set ::go 0
322 set v {1 1}
323 } else {
324 set v2 [expr {$msg=="" || $msg=="out of memory"}]
325 if {!$v2} {puts "\nError message returned: $msg"}
326 lappend v $v2
327 }
328 } {1 1}
329}
danielk1977b5548a82004-06-26 13:51:33 +0000330
331# Ensure that no file descriptors were leaked.
332do_test malloc-5.X {
333 catch {db close}
334 set sqlite_open_file_count
335} {0}
336
danielk197796fb0dd2004-06-30 09:49:22 +0000337for {set go 1; set i 1} {$go} {incr i} {
338 do_test malloc-6.$i {
339 sqlite_malloc_fail 0
340 catch {db close}
341 catch {file delete -force test.db}
342 catch {file delete -force test.db-journal}
343 sqlite3 db test.db
344 execsql {
345 BEGIN TRANSACTION;
346 CREATE TABLE t1(a);
347 INSERT INTO t1 VALUES(1);
348 INSERT INTO t1 SELECT a*2 FROM t1;
349 INSERT INTO t1 SELECT a*2 FROM t1;
350 INSERT INTO t1 SELECT a*2 FROM t1;
351 INSERT INTO t1 SELECT a*2 FROM t1;
352 INSERT INTO t1 SELECT a*2 FROM t1;
353 INSERT INTO t1 SELECT a*2 FROM t1;
354 INSERT INTO t1 SELECT a*2 FROM t1;
355 INSERT INTO t1 SELECT a*2 FROM t1;
356 INSERT INTO t1 SELECT a*2 FROM t1;
357 INSERT INTO t1 SELECT a*2 FROM t1;
358 DELETE FROM t1 where rowid%5 = 0;
359 COMMIT;
360 }
361 sqlite_malloc_fail $i
362 set v [catch {execsql {
363 VACUUM;
364 }} msg]
365 set leftover [lindex [sqlite_malloc_stat] 2]
366 if {$leftover>0} {
367 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
368 set ::go 0
369 set v {1 1}
370 } else {
371 set v2 [expr {$msg=="" || $msg=="out of memory"}]
372 if {!$v2} {puts "\nError message returned: $msg"}
373 lappend v $v2
374 }
375 } {1 1}
376}
377
danielk197701427a62005-01-11 13:02:33 +0000378for {set go 1; set i 1} {$go} {incr i} {
379 do_test malloc-7.$i {
380 sqlite_malloc_fail 0
381 catch {db close}
382 catch {file delete -force test.db}
383 catch {file delete -force test.db-journal}
384 sqlite3 db test.db
385 execsql {
386 CREATE TABLE t1(a, b);
387 INSERT INTO t1 VALUES(1, 2);
388 INSERT INTO t1 VALUES(3, 4);
389 INSERT INTO t1 VALUES(5, 6);
danielk1977b5402fb2005-01-12 07:15:04 +0000390 INSERT INTO t1 VALUES(7, randstr(1200,1200));
danielk197701427a62005-01-11 13:02:33 +0000391 }
392 sqlite_malloc_fail $i
393 set v [catch {execsql {
danielk1977b5402fb2005-01-12 07:15:04 +0000394 SELECT min(a) FROM t1 WHERE a<6 GROUP BY b;
395 SELECT a FROM t1 WHERE a<6 ORDER BY a;
396 SELECT b FROM t1 WHERE a>6;
danielk197701427a62005-01-11 13:02:33 +0000397 }} msg]
398 set leftover [lindex [sqlite_malloc_stat] 2]
399 if {$leftover>0} {
400 if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
401 set ::go 0
402 set v {1 1}
403 } else {
404 set v2 [expr {$msg=="" || $msg=="out of memory"}]
405 if {!$v2} {puts "\nError message returned: $msg"}
406 lappend v $v2
407 }
408 } {1 1}
409}
410
danielk1977b5402fb2005-01-12 07:15:04 +0000411# This block is designed to test that some malloc failures that may
412# occur in vdbeapi.c. Specifically, if a malloc failure that occurs
413# when converting UTF-16 text to integers and real numbers is handled
414# correctly.
415#
danielk19778b60e0f2005-01-12 09:10:39 +0000416# This is done by retrieving a string from the database engine and
417# manipulating it using the sqlite3_column_*** APIs. This doesn't
418# actually return an error to the user when a malloc() fails.. That
419# could be viewed as a bug.
420#
421# These tests only run if UTF-16 support is compiled in.
danielk1977b5402fb2005-01-12 07:15:04 +0000422#
423for {set go 1; set i 1} {$go && $::sqlite_options(utf16)} {incr i} {
424 do_test malloc-8.$i {
425 sqlite_malloc_fail 0
426 catch {db close}
427 catch {file delete -force test.db}
428 catch {file delete -force test.db-journal}
429
430 set ::DB [sqlite3 db test.db]
431 set sql "SELECT '[string repeat abc 20]', '[string repeat def 20]', ?"
432 set ::STMT [sqlite3_prepare $::DB $sql -1 X]
433 sqlite3_step $::STMT
434
435 if { $::tcl_platform(byteOrder)=="littleEndian" } {
436 set ::bomstr "\xFF\xFE"
437 } else {
438 set ::bomstr "\xFE\xFF"
439 }
440 append ::bomstr [encoding convertto unicode "123456789_123456789_12345678"]
441
442 sqlite_malloc_fail $i
443 catch {
444 sqlite3_column_text16 $::STMT 0
445 sqlite3_column_int $::STMT 0
446 sqlite3_column_text16 $::STMT 1
447 sqlite3_column_double $::STMT 1
448 sqlite3_reset $::STMT
449 sqlite3_bind_text16 $::STMT 1 $::bomstr 60
450
451 } msg
452 sqlite3_finalize $::STMT
453 if {[lindex [sqlite_malloc_stat] 2]>0} {
454 set ::go 0
455 }
456 expr 0
457 } {0}
458}
459
danielk19774397de52005-01-12 12:44:03 +0000460
danielk19778b60e0f2005-01-12 09:10:39 +0000461# This block tests that malloc() failures that occur whilst commiting
462# a multi-file transaction are handled correctly.
463#
danielk19774397de52005-01-12 12:44:03 +0000464do_malloc_test 9 -sqlprep {
465 ATTACH 'test2.db' as test2;
466 CREATE TABLE abc1(a, b, c);
467 CREATE TABLE test2.abc2(a, b, c);
468} -sqlbody {
469 BEGIN;
470 INSERT INTO abc1 VALUES(1, 2, 3);
471 INSERT INTO abc2 VALUES(1, 2, 3);
472 COMMIT;
danielk19778b60e0f2005-01-12 09:10:39 +0000473}
474
danielk19774397de52005-01-12 12:44:03 +0000475# This block tests malloc() failures that occur while opening a
476# connection to a database.
477do_malloc_test 10 -sqlprep {
478 CREATE TABLE abc(a, b, c);
479} -tclbody {
480 set ::DB [sqlite3 db2 test.db]
481 db2 eval {SELECT * FROM sqlite_master}
482 db2 close
483}
484
485# This block tests malloc() failures that occur within calls to
486# sqlite3_create_function().
487do_malloc_test 11 -tclbody {
danielk19772c336542005-01-13 02:14:23 +0000488 set rc [sqlite3_create_function $::DB]
489 if {[string match $rc SQLITE_NOMEM]} {
danielk19774397de52005-01-12 12:44:03 +0000490 error "out of memory"
491 }
492}
493
494do_malloc_test 12 -tclbody {
495 set sql16 [encoding convertto unicode "SELECT * FROM sqlite_master"]
496 append sql16 "\00\00"
497 set ::STMT [sqlite3_prepare16 $::DB $sql16 -1 DUMMY]
498 sqlite3_finalize $::STMT
499}
danielk19778b60e0f2005-01-12 09:10:39 +0000500
danielk197796fb0dd2004-06-30 09:49:22 +0000501# Ensure that no file descriptors were leaked.
danielk1977b5402fb2005-01-12 07:15:04 +0000502do_test malloc-99.X {
danielk197796fb0dd2004-06-30 09:49:22 +0000503 catch {db close}
504 set sqlite_open_file_count
505} {0}
506
drhed7c8552001-04-11 14:29:21 +0000507sqlite_malloc_fail 0
508finish_test