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.42 2007/05/30 10:36:47 danielk1977 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_MEMDEBUG..." 26 finish_test 27 return 28} 29 30source $testdir/malloc_common.tcl 31 32do_malloc_test 1 -tclprep { 33 db close 34} -tclbody { 35 if {[catch {sqlite3 db test.db}]} { 36 error "out of memory" 37 } 38} -sqlbody { 39 DROP TABLE IF EXISTS t1; 40 CREATE TABLE t1( 41 a int, b float, c double, d text, e varchar(20), 42 primary key(a,b,c) 43 ); 44 CREATE INDEX i1 ON t1(a,b); 45 INSERT INTO t1 VALUES(1,2.3,4.5,'hi',x'746865726500'); 46 INSERT INTO t1 VALUES(6,7.0,0.8,'hello','out yonder'); 47 SELECT * FROM t1; 48 SELECT avg(b) FROM t1 GROUP BY a HAVING b>20.0; 49 DELETE FROM t1 WHERE a IN (SELECT min(a) FROM t1); 50 SELECT count(*) FROM t1; 51} 52 53# Ensure that no file descriptors were leaked. 54do_test malloc-1.X { 55 catch {db close} 56 set sqlite_open_file_count 57} {0} 58 59do_malloc_test 2 -sqlbody { 60 CREATE TABLE t1(a int, b int default 'abc', c int default 1); 61 CREATE INDEX i1 ON t1(a,b); 62 INSERT INTO t1 VALUES(1,1,'99 abcdefghijklmnopqrstuvwxyz'); 63 INSERT INTO t1 VALUES(2,4,'98 abcdefghijklmnopqrstuvwxyz'); 64 INSERT INTO t1 VALUES(3,9,'97 abcdefghijklmnopqrstuvwxyz'); 65 INSERT INTO t1 VALUES(4,16,'96 abcdefghijklmnopqrstuvwxyz'); 66 INSERT INTO t1 VALUES(5,25,'95 abcdefghijklmnopqrstuvwxyz'); 67 INSERT INTO t1 VALUES(6,36,'94 abcdefghijklmnopqrstuvwxyz'); 68 SELECT 'stuff', count(*) as 'other stuff', max(a+10) FROM t1; 69 UPDATE t1 SET b=b||b||b||b; 70 UPDATE t1 SET b=a WHERE a in (10,12,22); 71 INSERT INTO t1(c,b,a) VALUES(20,10,5); 72 INSERT INTO t1 SELECT * FROM t1 73 WHERE a IN (SELECT a FROM t1 WHERE a<10); 74 DELETE FROM t1 WHERE a>=10; 75 DROP INDEX i1; 76 DELETE FROM t1; 77} 78 79# Ensure that no file descriptors were leaked. 80do_test malloc-2.X { 81 catch {db close} 82 set sqlite_open_file_count 83} {0} 84 85do_malloc_test 3 -sqlbody { 86 BEGIN TRANSACTION; 87 CREATE TABLE t1(a int, b int, c int); 88 CREATE INDEX i1 ON t1(a,b); 89 INSERT INTO t1 VALUES(1,1,99); 90 INSERT INTO t1 VALUES(2,4,98); 91 INSERT INTO t1 VALUES(3,9,97); 92 INSERT INTO t1 VALUES(4,16,96); 93 INSERT INTO t1 VALUES(5,25,95); 94 INSERT INTO t1 VALUES(6,36,94); 95 INSERT INTO t1(c,b,a) VALUES(20,10,5); 96 DELETE FROM t1 WHERE a>=10; 97 DROP INDEX i1; 98 DELETE FROM t1; 99 ROLLBACK; 100} 101 102 103# Ensure that no file descriptors were leaked. 104do_test malloc-3.X { 105 catch {db close} 106 set sqlite_open_file_count 107} {0} 108 109do_malloc_test 4 -sqlbody { 110 BEGIN TRANSACTION; 111 CREATE TABLE t1(a int, b int, c int); 112 CREATE INDEX i1 ON t1(a,b); 113 INSERT INTO t1 VALUES(1,1,99); 114 INSERT INTO t1 VALUES(2,4,98); 115 INSERT INTO t1 VALUES(3,9,97); 116 INSERT INTO t1 VALUES(4,16,96); 117 INSERT INTO t1 VALUES(5,25,95); 118 INSERT INTO t1 VALUES(6,36,94); 119 UPDATE t1 SET b=a WHERE a in (10,12,22); 120 INSERT INTO t1 SELECT * FROM t1 121 WHERE a IN (SELECT a FROM t1 WHERE a<10); 122 DROP INDEX i1; 123 DELETE FROM t1; 124 COMMIT; 125} 126 127# Ensure that no file descriptors were leaked. 128do_test malloc-4.X { 129 catch {db close} 130 set sqlite_open_file_count 131} {0} 132 133do_malloc_test 5 -sqlbody { 134 BEGIN TRANSACTION; 135 CREATE TABLE t1(a,b); 136 CREATE TABLE t2(x,y); 137 CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN 138 INSERT INTO t2(x,y) VALUES(new.rowid,1); 139 UPDATE t2 SET y=y+1 WHERE x=new.rowid; 140 SELECT 123; 141 DELETE FROM t2 WHERE x=new.rowid; 142 END; 143 INSERT INTO t1(a,b) VALUES(2,3); 144 COMMIT; 145} 146 147# Ensure that no file descriptors were leaked. 148do_test malloc-5.X { 149 catch {db close} 150 set sqlite_open_file_count 151} {0} 152 153do_malloc_test 6 -sqlprep { 154 BEGIN TRANSACTION; 155 CREATE TABLE t1(a); 156 INSERT INTO t1 VALUES(1); 157 INSERT INTO t1 SELECT a*2 FROM t1; 158 INSERT INTO t1 SELECT a*2 FROM t1; 159 INSERT INTO t1 SELECT a*2 FROM t1; 160 INSERT INTO t1 SELECT a*2 FROM t1; 161 INSERT INTO t1 SELECT a*2 FROM t1; 162 INSERT INTO t1 SELECT a*2 FROM t1; 163 INSERT INTO t1 SELECT a*2 FROM t1; 164 INSERT INTO t1 SELECT a*2 FROM t1; 165 INSERT INTO t1 SELECT a*2 FROM t1; 166 INSERT INTO t1 SELECT a*2 FROM t1; 167 DELETE FROM t1 where rowid%5 = 0; 168 COMMIT; 169} -sqlbody { 170 VACUUM; 171} 172 173do_malloc_test 7 -sqlprep { 174 CREATE TABLE t1(a, b); 175 INSERT INTO t1 VALUES(1, 2); 176 INSERT INTO t1 VALUES(3, 4); 177 INSERT INTO t1 VALUES(5, 6); 178 INSERT INTO t1 VALUES(7, randstr(1200,1200)); 179} -sqlbody { 180 SELECT min(a) FROM t1 WHERE a<6 GROUP BY b; 181 SELECT a FROM t1 WHERE a<6 ORDER BY a; 182 SELECT b FROM t1 WHERE a>6; 183} 184 185# This block is designed to test that some malloc failures that may 186# occur in vdbeapi.c. Specifically, if a malloc failure that occurs 187# when converting UTF-16 text to integers and real numbers is handled 188# correctly. 189# 190# This is done by retrieving a string from the database engine and 191# manipulating it using the sqlite3_column_*** APIs. This doesn't 192# actually return an error to the user when a malloc() fails.. That 193# could be viewed as a bug. 194# 195# These tests only run if UTF-16 support is compiled in. 196# 197if {$::sqlite_options(utf16)} { 198 do_malloc_test 8 -tclprep { 199 set sql "SELECT '[string repeat abc 20]', '[string repeat def 20]', ?" 200 set ::STMT [sqlite3_prepare $::DB $sql -1 X] 201 sqlite3_step $::STMT 202 if { $::tcl_platform(byteOrder)=="littleEndian" } { 203 set ::bomstr "\xFF\xFE" 204 } else { 205 set ::bomstr "\xFE\xFF" 206 } 207 append ::bomstr [encoding convertto unicode "123456789_123456789_12345678"] 208 } -tclbody { 209 sqlite3_column_text16 $::STMT 0 210 sqlite3_column_int $::STMT 0 211 sqlite3_column_text16 $::STMT 1 212 sqlite3_column_double $::STMT 1 213 sqlite3_reset $::STMT 214 sqlite3_bind_text16 $::STMT 1 $::bomstr 60 215 catch {sqlite3_finalize $::STMT} 216 if {[lindex [sqlite_malloc_stat] 2]<=0} { 217 error "out of memory" 218 } 219 } -cleanup { 220 sqlite3_finalize $::STMT 221 } 222} 223 224# This block tests that malloc() failures that occur whilst commiting 225# a multi-file transaction are handled correctly. 226# 227do_malloc_test 9 -sqlprep { 228 ATTACH 'test2.db' as test2; 229 CREATE TABLE abc1(a, b, c); 230 CREATE TABLE test2.abc2(a, b, c); 231} -sqlbody { 232 BEGIN; 233 INSERT INTO abc1 VALUES(1, 2, 3); 234 INSERT INTO abc2 VALUES(1, 2, 3); 235 COMMIT; 236} 237 238# This block tests malloc() failures that occur while opening a 239# connection to a database. 240do_malloc_test 10 -sqlprep { 241 CREATE TABLE abc(a, b, c); 242} -tclbody { 243 db close 244 sqlite3 db2 test.db 245 db2 eval {SELECT * FROM sqlite_master} 246 db2 close 247} 248 249# This block tests malloc() failures that occur within calls to 250# sqlite3_create_function(). 251do_malloc_test 11 -tclbody { 252 set rc [sqlite3_create_function $::DB] 253 if {[string match $rc SQLITE_NOMEM]} { 254 error "out of memory" 255 } 256} 257 258do_malloc_test 12 -tclbody { 259 set sql16 [encoding convertto unicode "SELECT * FROM sqlite_master"] 260 append sql16 "\00\00" 261 set ::STMT [sqlite3_prepare16 $::DB $sql16 -1 DUMMY] 262 sqlite3_finalize $::STMT 263} 264 265# Test malloc errors when replaying two hot journals from a 2-file 266# transaction. 267ifcapable crashtest { 268 do_malloc_test 13 -tclprep { 269 set rc [crashsql -delay 1 -file test2.db { 270 ATTACH 'test2.db' as aux; 271 PRAGMA cache_size = 10; 272 BEGIN; 273 CREATE TABLE aux.t2(a, b, c); 274 CREATE TABLE t1(a, b, c); 275 COMMIT; 276 }] 277 if {$rc!="1 {child process exited abnormally}"} { 278 error "Wrong error message: $rc" 279 } 280 } -tclbody { 281 db eval {ATTACH 'test2.db' as aux;} 282 set rc [catch {db eval { 283 SELECT * FROM t1; 284 SELECT * FROM t2; 285 }} err] 286 if {$rc && $err!="no such table: t1"} { 287 error $err 288 } 289 } 290} 291 292if {$tcl_platform(platform)!="windows"} { 293 do_malloc_test 14 -tclprep { 294 catch {db close} 295 sqlite3 db2 test2.db 296 db2 eval { 297 PRAGMA synchronous = 0; 298 CREATE TABLE t1(a, b); 299 INSERT INTO t1 VALUES(1, 2); 300 BEGIN; 301 INSERT INTO t1 VALUES(3, 4); 302 } 303 copy_file test2.db test.db 304 copy_file test2.db-journal test.db-journal 305 db2 close 306 } -tclbody { 307 sqlite3 db test.db 308 db eval { 309 SELECT * FROM t1; 310 } 311 } 312} 313 314proc string_compare {a b} { 315 return [string compare $a $b] 316} 317 318# Test for malloc() failures in sqlite3_create_collation() and 319# sqlite3_create_collation16(). 320# 321do_malloc_test 15 -tclbody { 322 db collate string_compare string_compare 323 if {[catch {add_test_collate $::DB 1 1 1} msg]} { 324 if {$msg=="SQLITE_NOMEM"} {set msg "out of memory"} 325 error $msg 326 } 327 328 db complete {SELECT "hello """||'world"' [microsoft], * FROM anicetable;} 329 db complete {-- Useful comment} 330 331 execsql { 332 CREATE TABLE t1(a, b COLLATE string_compare); 333 INSERT INTO t1 VALUES(10, 'string'); 334 INSERT INTO t1 VALUES(10, 'string2'); 335 } 336} 337 338# Also test sqlite3_complete(). There are (currently) no malloc() 339# calls in this function, but test anyway against future changes. 340# 341do_malloc_test 16 -tclbody { 342 db complete {SELECT "hello """||'world"' [microsoft], * FROM anicetable;} 343 db complete {-- Useful comment} 344 db eval { 345 SELECT * FROM sqlite_master; 346 } 347} 348 349# Test handling of malloc() failures in sqlite3_open16(). 350# 351do_malloc_test 17 -tclbody { 352 set DB2 0 353 set STMT 0 354 355 # open database using sqlite3_open16() 356 set filename [encoding convertto unicode test.db] 357 append filename "\x00\x00" 358 set DB2 [sqlite3_open16 $filename -unused] 359 if {0==$DB2} { 360 error "out of memory" 361 } 362 363 # Prepare statement 364 set rc [catch {sqlite3_prepare $DB2 {SELECT * FROM sqlite_master} -1 X} msg] 365 if {$rc} { 366 error [string range $msg 4 end] 367 } 368 set STMT $msg 369 370 # Finalize statement 371 set rc [sqlite3_finalize $STMT] 372 if {$rc!="SQLITE_OK"} { 373 error [sqlite3_errmsg $DB2] 374 } 375 set STMT 0 376 377 # Close database 378 set rc [sqlite3_close $DB2] 379 if {$rc!="SQLITE_OK"} { 380 error [sqlite3_errmsg $DB2] 381 } 382 set DB2 0 383} -cleanup { 384 if {$STMT!="0"} { 385 sqlite3_finalize $STMT 386 } 387 if {$DB2!="0"} { 388 set rc [sqlite3_close $DB2] 389 } 390} 391 392# Test handling of malloc() failures in sqlite3_errmsg16(). 393# 394do_malloc_test 18 -tclbody { 395 catch { 396 db eval "SELECT [string repeat longcolumnname 10] FROM sqlite_master" 397 } msg 398 if {$msg=="out of memory"} {error $msg} 399 set utf16 [sqlite3_errmsg16 [sqlite3_connection_pointer db]] 400 binary scan $utf16 c* bytes 401 if {[llength $bytes]==0} { 402 error "out of memory" 403 } 404} 405 406# This test is aimed at coverage testing. Specificly, it is supposed to 407# cause a malloc() only used when converting between the two utf-16 408# encodings to fail (i.e. little-endian->big-endian). It only actually 409# hits this malloc() on little-endian hosts. 410# 411set static_string "\x00h\x00e\x00l\x00l\x00o" 412for {set l 0} {$l<10} {incr l} { 413 append static_string $static_string 414} 415append static_string "\x00\x00" 416do_malloc_test 19 -tclprep { 417 execsql { 418 PRAGMA encoding = "UTF16be"; 419 CREATE TABLE abc(a, b, c); 420 } 421} -tclbody { 422 unset -nocomplain ::STMT 423 set r [catch { 424 set ::STMT [sqlite3_prepare $::DB {SELECT ?} -1 DUMMY] 425 sqlite3_bind_text16 -static $::STMT 1 $static_string 112 426 } msg] 427 if {$r} {error [string range $msg 4 end]} 428 set msg 429} -cleanup { 430 if {[info exists ::STMT]} { 431 sqlite3_finalize $::STMT 432 } 433} 434unset static_string 435 436# Make sure SQLITE_NOMEM is reported out on an ATTACH failure even 437# when the malloc failure occurs within the nested parse. 438# 439do_malloc_test 20 -tclprep { 440 db close 441 file delete -force test2.db test2.db-journal 442 sqlite3 db test2.db 443 db eval {CREATE TABLE t1(x);} 444 db close 445} -tclbody { 446 if {[catch {sqlite3 db test.db}]} { 447 error "out of memory" 448 } 449} -sqlbody { 450 ATTACH DATABASE 'test2.db' AS t2; 451 SELECT * FROM t1; 452 DETACH DATABASE t2; 453} 454 455# Test malloc failure whilst installing a foreign key. 456# 457do_malloc_test 21 -sqlbody { 458 CREATE TABLE abc(a, b, c, FOREIGN KEY(a) REFERENCES abc(b)) 459} 460 461# Test malloc failure in an sqlite3_prepare_v2() call. 462# 463do_malloc_test 22 -tclbody { 464 set ::STMT "" 465 set r [catch { 466 set ::STMT [ 467 sqlite3_prepare_v2 $::DB "SELECT * FROM sqlite_master" -1 DUMMY 468 ] 469 } msg] 470 if {$r} {error [string range $msg 4 end]} 471} -cleanup { 472 if {$::STMT ne ""} { 473 sqlite3_finalize $::STMT 474 set ::STMT "" 475 } 476} 477 478# Ensure that no file descriptors were leaked. 479do_test malloc-99.X { 480 catch {db close} 481 set sqlite_open_file_count 482} {0} 483 484puts open-file-count=$sqlite_open_file_count 485sqlite_malloc_fail 0 486finish_test 487