1# 2001 September 15 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 attempts to check the library in an out-of-memory situation. 12# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special 13# command (sqlite_malloc_fail N) which causes the N-th malloc to fail. This 14# 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# 17# $Id: malloc.test,v 1.24 2005/09/08 00:13:28 drh Exp $ 18 19set testdir [file dirname $argv0] 20source $testdir/tester.tcl 21 22# Only run these tests if memory debugging is turned on. 23# 24if {[info command sqlite_malloc_stat]==""} { 25 puts "Skipping malloc tests: not compiled with -DSQLITE_DEBUG..." 26 finish_test 27 return 28} 29 30# 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. 37# -tclbody TCL script to run with malloc failure simulation. 38# -sqlbody TCL script to run with malloc failure simulation. 39# -cleanup TCL script to run after the test. 40# 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. 53# 54proc do_malloc_test {tn args} { 55 array set ::mallocopts $args 56 57 set ::go 1 58 for {set ::n 1} {$::go} {incr ::n} { 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 if {[info exists ::mallocopts(-cleanup)]} { 100 catch $::mallocopts(-cleanup) 101 } 102 } 103 unset ::mallocopts 104} 105 106do_malloc_test 1 -tclprep { 107 db close 108} -tclbody { 109 if {[catch {sqlite3 db test.db}]} { 110 error "out of memory" 111 } 112} -sqlbody { 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} 125 126# Ensure that no file descriptors were leaked. 127do_test malloc-1.X { 128 catch {db close} 129 set sqlite_open_file_count 130} {0} 131 132do_malloc_test 2 -sqlbody { 133 CREATE TABLE t1(a int, b int default 'abc', c int default 1); 134 CREATE INDEX i1 ON t1(a,b); 135 INSERT INTO t1 VALUES(1,1,'99 abcdefghijklmnopqrstuvwxyz'); 136 INSERT INTO t1 VALUES(2,4,'98 abcdefghijklmnopqrstuvwxyz'); 137 INSERT INTO t1 VALUES(3,9,'97 abcdefghijklmnopqrstuvwxyz'); 138 INSERT INTO t1 VALUES(4,16,'96 abcdefghijklmnopqrstuvwxyz'); 139 INSERT INTO t1 VALUES(5,25,'95 abcdefghijklmnopqrstuvwxyz'); 140 INSERT INTO t1 VALUES(6,36,'94 abcdefghijklmnopqrstuvwxyz'); 141 SELECT 'stuff', count(*) as 'other stuff', max(a+10) FROM t1; 142 UPDATE t1 SET b=b||b||b||b; 143 UPDATE t1 SET b=a WHERE a in (10,12,22); 144 INSERT INTO t1(c,b,a) VALUES(20,10,5); 145 INSERT INTO t1 SELECT * FROM t1 146 WHERE a IN (SELECT a FROM t1 WHERE a<10); 147 DELETE FROM t1 WHERE a>=10; 148 DROP INDEX i1; 149 DELETE FROM t1; 150} 151 152# Ensure that no file descriptors were leaked. 153do_test malloc-2.X { 154 catch {db close} 155 set sqlite_open_file_count 156} {0} 157 158do_malloc_test 3 -sqlbody { 159 BEGIN TRANSACTION; 160 CREATE TABLE t1(a int, b int, c int); 161 CREATE INDEX i1 ON t1(a,b); 162 INSERT INTO t1 VALUES(1,1,99); 163 INSERT INTO t1 VALUES(2,4,98); 164 INSERT INTO t1 VALUES(3,9,97); 165 INSERT INTO t1 VALUES(4,16,96); 166 INSERT INTO t1 VALUES(5,25,95); 167 INSERT INTO t1 VALUES(6,36,94); 168 INSERT INTO t1(c,b,a) VALUES(20,10,5); 169 DELETE FROM t1 WHERE a>=10; 170 DROP INDEX i1; 171 DELETE FROM t1; 172 ROLLBACK; 173} 174 175 176# Ensure that no file descriptors were leaked. 177do_test malloc-3.X { 178 catch {db close} 179 set sqlite_open_file_count 180} {0} 181 182do_malloc_test 4 -sqlbody { 183 BEGIN TRANSACTION; 184 CREATE TABLE t1(a int, b int, c int); 185 CREATE INDEX i1 ON t1(a,b); 186 INSERT INTO t1 VALUES(1,1,99); 187 INSERT INTO t1 VALUES(2,4,98); 188 INSERT INTO t1 VALUES(3,9,97); 189 INSERT INTO t1 VALUES(4,16,96); 190 INSERT INTO t1 VALUES(5,25,95); 191 INSERT INTO t1 VALUES(6,36,94); 192 UPDATE t1 SET b=a WHERE a in (10,12,22); 193 INSERT INTO t1 SELECT * FROM t1 194 WHERE a IN (SELECT a FROM t1 WHERE a<10); 195 DROP INDEX i1; 196 DELETE FROM t1; 197 COMMIT; 198} 199 200# Ensure that no file descriptors were leaked. 201do_test malloc-4.X { 202 catch {db close} 203 set sqlite_open_file_count 204} {0} 205 206do_malloc_test 5 -sqlbody { 207 BEGIN TRANSACTION; 208 CREATE TABLE t1(a,b); 209 CREATE TABLE t2(x,y); 210 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN 211 INSERT INTO t2(x,y) VALUES(new.rowid,1); 212 END; 213 INSERT INTO t1(a,b) VALUES(2,3); 214 COMMIT; 215} 216 217# Ensure that no file descriptors were leaked. 218do_test malloc-5.X { 219 catch {db close} 220 set sqlite_open_file_count 221} {0} 222 223do_malloc_test 6 -sqlprep { 224 BEGIN TRANSACTION; 225 CREATE TABLE t1(a); 226 INSERT INTO t1 VALUES(1); 227 INSERT INTO t1 SELECT a*2 FROM t1; 228 INSERT INTO t1 SELECT a*2 FROM t1; 229 INSERT INTO t1 SELECT a*2 FROM t1; 230 INSERT INTO t1 SELECT a*2 FROM t1; 231 INSERT INTO t1 SELECT a*2 FROM t1; 232 INSERT INTO t1 SELECT a*2 FROM t1; 233 INSERT INTO t1 SELECT a*2 FROM t1; 234 INSERT INTO t1 SELECT a*2 FROM t1; 235 INSERT INTO t1 SELECT a*2 FROM t1; 236 INSERT INTO t1 SELECT a*2 FROM t1; 237 DELETE FROM t1 where rowid%5 = 0; 238 COMMIT; 239} -sqlbody { 240 VACUUM; 241} 242 243do_malloc_test 7 -sqlprep { 244 CREATE TABLE t1(a, b); 245 INSERT INTO t1 VALUES(1, 2); 246 INSERT INTO t1 VALUES(3, 4); 247 INSERT INTO t1 VALUES(5, 6); 248 INSERT INTO t1 VALUES(7, randstr(1200,1200)); 249} -sqlbody { 250 SELECT min(a) FROM t1 WHERE a<6 GROUP BY b; 251 SELECT a FROM t1 WHERE a<6 ORDER BY a; 252 SELECT b FROM t1 WHERE a>6; 253} 254 255# This block is designed to test that some malloc failures that may 256# occur in vdbeapi.c. Specifically, if a malloc failure that occurs 257# when converting UTF-16 text to integers and real numbers is handled 258# correctly. 259# 260# This is done by retrieving a string from the database engine and 261# manipulating it using the sqlite3_column_*** APIs. This doesn't 262# actually return an error to the user when a malloc() fails.. That 263# could be viewed as a bug. 264# 265# These tests only run if UTF-16 support is compiled in. 266# 267if {$::sqlite_options(utf16)} { 268 do_malloc_test 8 -tclprep { 269 set sql "SELECT '[string repeat abc 20]', '[string repeat def 20]', ?" 270 set ::STMT [sqlite3_prepare $::DB $sql -1 X] 271 sqlite3_step $::STMT 272 if { $::tcl_platform(byteOrder)=="littleEndian" } { 273 set ::bomstr "\xFF\xFE" 274 } else { 275 set ::bomstr "\xFE\xFF" 276 } 277 append ::bomstr [encoding convertto unicode "123456789_123456789_12345678"] 278 } -tclbody { 279 sqlite3_column_text16 $::STMT 0 280 sqlite3_column_int $::STMT 0 281 sqlite3_column_text16 $::STMT 1 282 sqlite3_column_double $::STMT 1 283 sqlite3_reset $::STMT 284 sqlite3_bind_text16 $::STMT 1 $::bomstr 60 285 catch {sqlite3_finalize $::STMT} 286 if {[lindex [sqlite_malloc_stat] 2]<=0} { 287 error "out of memory" 288 } 289 } -cleanup { 290 sqlite3_finalize $::STMT 291 } 292} 293 294# This block tests that malloc() failures that occur whilst commiting 295# a multi-file transaction are handled correctly. 296# 297do_malloc_test 9 -sqlprep { 298 ATTACH 'test2.db' as test2; 299 CREATE TABLE abc1(a, b, c); 300 CREATE TABLE test2.abc2(a, b, c); 301} -sqlbody { 302 BEGIN; 303 INSERT INTO abc1 VALUES(1, 2, 3); 304 INSERT INTO abc2 VALUES(1, 2, 3); 305 COMMIT; 306} 307 308# This block tests malloc() failures that occur while opening a 309# connection to a database. 310do_malloc_test 10 -sqlprep { 311 CREATE TABLE abc(a, b, c); 312} -tclbody { 313 set ::DB [sqlite3 db2 test.db] 314 db2 eval {SELECT * FROM sqlite_master} 315 db2 close 316} 317 318# This block tests malloc() failures that occur within calls to 319# sqlite3_create_function(). 320do_malloc_test 11 -tclbody { 321 set rc [sqlite3_create_function $::DB] 322 if {[string match $rc SQLITE_NOMEM]} { 323 error "out of memory" 324 } 325} 326 327do_malloc_test 12 -tclbody { 328 set sql16 [encoding convertto unicode "SELECT * FROM sqlite_master"] 329 append sql16 "\00\00" 330 set ::STMT [sqlite3_prepare16 $::DB $sql16 -1 DUMMY] 331 sqlite3_finalize $::STMT 332} 333 334# Test malloc errors when replaying two hot journals from a 2-file 335# transaction. This test only runs on UNIX. 336if {$tcl_platform(platform)=="unix"} { 337 do_malloc_test 13 -tclprep { 338 set rc [crashsql 1 test2.db { 339 ATTACH 'test2.db' as aux; 340 PRAGMA cache_size = 10; 341 BEGIN; 342 CREATE TABLE aux.t2(a, b, c); 343 CREATE TABLE t1(a, b, c); 344 COMMIT; 345 }] 346 if {$rc!="1 {child process exited abnormally}"} { 347 error "Wrong error message: $rc" 348 } 349 } -sqlbody { 350 ATTACH 'test2.db' as aux; 351 SELECT * FROM t1; 352 SELECT * FROM t2; 353 } 354} 355 356if {$tcl_platform(platform)!="windows"} { 357do_malloc_test 14 -tclprep { 358 catch {db close} 359 sqlite3 db2 test2.db 360 db2 eval { 361 PRAGMA synchronous = 0; 362 CREATE TABLE t1(a, b); 363 INSERT INTO t1 VALUES(1, 2); 364 BEGIN; 365 INSERT INTO t1 VALUES(3, 4); 366 } 367 copy_file test2.db test.db 368 copy_file test2.db-journal test.db-journal 369 db2 close 370} -tclbody { 371 sqlite3 db test.db 372 db eval { 373 SELECT * FROM t1; 374 } 375} 376} 377 378# Ensure that no file descriptors were leaked. 379do_test malloc-99.X { 380 catch {db close} 381 set sqlite_open_file_count 382} {0} 383 384sqlite_malloc_fail 0 385finish_test 386