diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/malloc2.test | 40 | ||||
-rw-r--r-- | test/malloc3.test | 15 | ||||
-rw-r--r-- | test/malloc4.test | 61 | ||||
-rw-r--r-- | test/malloc5.test | 21 | ||||
-rw-r--r-- | test/malloc6.test | 107 | ||||
-rw-r--r-- | test/malloc7.test | 110 | ||||
-rw-r--r-- | test/malloc8.test | 140 | ||||
-rw-r--r-- | test/malloc9.test | 97 | ||||
-rw-r--r-- | test/mallocA.test | 107 | ||||
-rw-r--r-- | test/mallocB.test | 6 | ||||
-rw-r--r-- | test/mallocC.test | 16 | ||||
-rw-r--r-- | test/malloc_common.tcl | 3 | ||||
-rw-r--r-- | test/tester.tcl | 62 |
13 files changed, 139 insertions, 646 deletions
diff --git a/test/malloc2.test b/test/malloc2.test index d80d6f89f..0baee2a13 100644 --- a/test/malloc2.test +++ b/test/malloc2.test @@ -8,25 +8,25 @@ # May you share freely, never taking more than you give. # #*********************************************************************** +# # This file attempts to check that the library can recover from a malloc() # failure when sqlite3_global_recover() is invoked. # -# $Id: malloc2.test,v 1.5 2006/09/04 18:54:14 drh Exp $ +# (Later:) The sqlite3_global_recover() interface is now a no-op. +# Recovery from malloc() failures is automatic. But we keep these +# tests around because you can never have too many test cases. +# +# $Id: malloc2.test,v 1.6 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { - puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG=1" - finish_test - return -} - -ifcapable !globalrecover { - finish_test - return +ifcapable !memdebug { + puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." + finish_test + return } # Generate a checksum based on the contents of the database. If the @@ -65,7 +65,7 @@ proc do_malloc2_test {tn args} { # Run the SQL. Malloc number $::n is set to fail. A malloc() failure # may or may not be reported. - sqlite_malloc_fail $::n + sqlite3_memdebug_fail $::n 1 do_test malloc2-$tn.$::n.2 { set res [catchsql [string trim $::mallocopts(-sql)]] set rc [expr { @@ -80,21 +80,19 @@ proc do_malloc2_test {tn args} { # If $::n is greater than the number of malloc() calls required to # execute the SQL, then this test is finished. Break out of the loop. - if {[lindex [sqlite_malloc_stat] 2]>0} { - sqlite_malloc_fail -1 - break - } + set nFail [sqlite3_memdebug_fail -1 -1] + if {$nFail==0} break # Nothing should work now, because the allocator should refuse to # allocate any memory. # # Update: SQLite now automatically recovers from a malloc() failure. # So the statement in the test below would work. -if 0 { - do_test malloc2-$tn.$::n.3 { - catchsql {SELECT 'nothing should work'} - } {1 {out of memory}} -} + if 0 { + do_test malloc2-$tn.$::n.3 { + catchsql {SELECT 'nothing should work'} + } {1 {out of memory}} + } # Recover from the malloc failure. # @@ -118,7 +116,7 @@ if 0 { } $sum integrity_check malloc2-$tn.$::n.6 - if {$::nErr>1} return + if {$::nErr>1} return } unset ::mallocopts } diff --git a/test/malloc3.test b/test/malloc3.test index a3d4ddf8a..d96519d59 100644 --- a/test/malloc3.test +++ b/test/malloc3.test @@ -13,13 +13,14 @@ # correctly. The emphasis of these tests are the _prepare(), _step() and # _finalize() calls. # -# $Id: malloc3.test,v 1.10 2007/03/28 01:59:34 drh Exp $ +# $Id: malloc3.test,v 1.11 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. -if {[info command sqlite_malloc_stat]==""} { +# +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return @@ -559,7 +560,7 @@ proc run_test {arglist {pcstart 0} {iFailStart 1}} { set ::rollback_hook_count 0 set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit - sqlite_malloc_fail $iFail + sqlite3_memdebug_fail $iFail 1 set rc [catch {db eval [lindex $v 1]} msg] ;# True error occurs set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit @@ -574,11 +575,12 @@ proc run_test {arglist {pcstart 0} {iFailStart 1}} { } {1} } + set nFail [sqlite3_memdebug_fail -1 -1] if {$rc == 0} { # Successful execution of sql. Our "mallocs-until-failure" # count should be greater than 0. Otherwise a malloc() failed # and the error was not reported. - if {[lindex [sqlite_malloc_stat] 2] <= 0} { + if {$nFail>0} { error "Unreported malloc() failure" } @@ -591,7 +593,6 @@ proc run_test {arglist {pcstart 0} {iFailStart 1}} { incr pc set iFail 1 - sqlite_malloc_fail 0 integrity_check "malloc3-(integrity).$iterid" } elseif {[regexp {.*out of memory} $msg]} { # Out of memory error, as expected @@ -638,9 +639,7 @@ db cache size 0 run_test $::run_test_script 9 1 # run_test [lrange $::run_test_script 0 3] 0 63 -sqlite_malloc_fail 0 +sqlite3_memdebug_fail -1 -1 db close -pp_check_for_leaks - finish_test diff --git a/test/malloc4.test b/test/malloc4.test index af48f234f..1ce95b924 100644 --- a/test/malloc4.test +++ b/test/malloc4.test @@ -12,7 +12,7 @@ # This file contains tests to ensure that the library handles malloc() failures # correctly. The emphasis in this file is on sqlite3_column_XXX() APIs. # -# $Id: malloc4.test,v 1.3 2006/01/23 07:52:41 danielk1977 Exp $ +# $Id: malloc4.test,v 1.4 2007/08/22 22:04:37 drh Exp $ #--------------------------------------------------------------------------- # NOTES ON EXPECTED BEHAVIOUR @@ -27,7 +27,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. -if {[info command sqlite_malloc_stat]==""} { +if {[info command sqlite3_memdebug_pending]==""} { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return @@ -42,7 +42,7 @@ proc do_stmt_test {id sql} { set ::sql $sql set go 1 for {set n 1} {$go} {incr n} { - set testid "malloc4-$id.(iFail $n)" + set testid "malloc4-$id.$n" # Prepare the statement do_test ${testid}.1 { @@ -51,7 +51,7 @@ proc do_stmt_test {id sql} { } {1} # Set the Nth malloc() to fail. - sqlite_malloc_fail $n + sqlite3_memdebug_fail $n 1 # Test malloc failure in the _name(), _name16(), decltype() and # decltype16() APIs. Calls that occur after the malloc() failure should @@ -69,26 +69,26 @@ proc do_stmt_test {id sql} { # about explicitly testing them. # do_test ${testid}.2.1 { - set mf1 [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set mf1 [expr [sqlite3_memdebug_pending] <= 0] set ::name8 [sqlite3_column_name $::STMT 0] - set mf2 [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set mf2 [expr [sqlite3_memdebug_pending] <= 0] expr {$mf1 == $mf2 || $::name8 == ""} } {1} do_test ${testid}.2.2 { - set mf1 [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set mf1 [expr [sqlite3_memdebug_pending] <= 0] set ::name16 [sqlite3_column_name16 $::STMT 0] set ::name16 [encoding convertfrom unicode $::name16] set ::name16 [string range $::name16 0 end-1] - set mf2 [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set mf2 [expr [sqlite3_memdebug_pending] <= 0] expr {$mf1 == $mf2 || $::name16 == ""} } {1} do_test ${testid}.2.3 { - set mf1 [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set mf1 [expr [sqlite3_memdebug_pending] <= 0] set ::name8_2 [sqlite3_column_name $::STMT 0] - set mf2 [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set mf2 [expr [sqlite3_memdebug_pending] <= 0] expr {$mf1 == $mf2 || $::name8_2 == ""} } {1} - set ::mallocFailed [expr [lindex [sqlite_malloc_stat] 2] <= 0] + set ::mallocFailed [expr [sqlite3_memdebug_pending] <= 0] do_test ${testid}.2.4 { expr { $::name8 == $::name8_2 && $::name16 == $::name8 && !$::mallocFailed || @@ -102,30 +102,30 @@ proc do_stmt_test {id sql} { # running sqlite3_step(), make sure that malloc() is not about to fail. # Memory allocation failures that occur within sqlite3_step() are tested # elsewhere. - set mf [lindex [sqlite_malloc_stat] 2] - sqlite_malloc_fail 0 + set mf [sqlite3_memdebug_pending] + sqlite3_memdebug_fail -1 do_test ${testid}.3 { sqlite3_step $::STMT } {SQLITE_ROW} - sqlite_malloc_fail $mf + sqlite3_memdebug_fail $mf # Test for malloc() failures within _text() and _text16(). # do_test ${testid}.4.1 { set ::text8 [sqlite3_column_text $::STMT 0] - set mf [expr [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed] + set mf [expr [sqlite3_memdebug_pending] <= 0 && !$::mallocFailed] expr {$mf==0 || $::text8 == ""} } {1} do_test ${testid}.4.2 { set ::text16 [sqlite3_column_text16 $::STMT 0] set ::text16 [encoding convertfrom unicode $::text16] set ::text16 [string range $::text16 0 end-1] - set mf [expr [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed] + set mf [expr [sqlite3_memdebug_pending] <= 0 && !$::mallocFailed] expr {$mf==0 || $::text16 == ""} } {1} do_test ${testid}.4.3 { set ::text8_2 [sqlite3_column_text $::STMT 0] - set mf [expr [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed] + set mf [expr [sqlite3_memdebug_pending] <= 0 && !$::mallocFailed] expr {$mf==0 || $::text8_2 == "" || ($::text16 == "" && $::text8 != "")} } {1} @@ -133,33 +133,33 @@ proc do_stmt_test {id sql} { # way this can occur is if the string has to be translated from UTF-16 to # UTF-8 before being converted to a numeric value. do_test ${testid}.4.4.1 { - set mf [lindex [sqlite_malloc_stat] 2] - sqlite_malloc_fail 0 + set mf [sqlite3_memdebug_pending] + sqlite3_memdebug_fail -1 sqlite3_column_text16 $::STMT 0 - sqlite_malloc_fail $mf + sqlite3_memdebug_fail $mf sqlite3_column_int $::STMT 0 } {0} do_test ${testid}.4.5 { - set mf [lindex [sqlite_malloc_stat] 2] - sqlite_malloc_fail 0 + set mf [sqlite3_memdebug_pending] + sqlite3_memdebug_fail -1 sqlite3_column_text16 $::STMT 0 - sqlite_malloc_fail $mf + sqlite3_memdebug_fail $mf sqlite3_column_int64 $::STMT 0 } {0} do_test ${testid}.4.6 { - set mf [lindex [sqlite_malloc_stat] 2] - sqlite_malloc_fail 0 + set mf [sqlite3_memdebug_pending] + sqlite3_memdebug_fail -1 sqlite3_column_text16 $::STMT 0 - sqlite_malloc_fail $mf + sqlite3_memdebug_fail $mf sqlite3_column_double $::STMT 0 } {0.0} set mallocFailedAfterStep [expr \ - [lindex [sqlite_malloc_stat] 2] <= 0 && !$::mallocFailed + [sqlite3_memdebug_pending] <= 0 && !$::mallocFailed ] - sqlite_malloc_fail 0 + sqlite3_memdebug_fail -1 # Test that if a malloc() failed the next call to sqlite3_step() returns # SQLITE_ERROR. If malloc() did not fail, it should return SQLITE_DONE. # @@ -172,7 +172,7 @@ proc do_stmt_test {id sql} { } [expr {$mallocFailedAfterStep ? "SQLITE_NOMEM" : "SQLITE_OK"}] if {$::mallocFailed == 0 && $mallocFailedAfterStep == 0} { - sqlite_malloc_fail 0 + sqlite3_memdebug_fail -1 set go 0 } } @@ -189,6 +189,5 @@ execsql { do_stmt_test 1 "SELECT * FROM tbl" -sqlite_malloc_fail 0 +sqlite3_memdebug_fail -1 finish_test - diff --git a/test/malloc5.test b/test/malloc5.test index 4f5b7fff2..a45bf8efc 100644 --- a/test/malloc5.test +++ b/test/malloc5.test @@ -12,7 +12,7 @@ # This file contains test cases focused on the two memory-management APIs, # sqlite3_soft_heap_limit() and sqlite3_release_memory(). # -# $Id: malloc5.test,v 1.12 2007/08/12 20:07:59 drh Exp $ +# $Id: malloc5.test,v 1.13 2007/08/22 22:04:37 drh Exp $ #--------------------------------------------------------------------------- # NOTES ON EXPECTED BEHAVIOUR @@ -25,7 +25,8 @@ source $testdir/tester.tcl db close # Only run these tests if memory debugging is turned on. -if {[info command sqlite_malloc_stat]==""} { +# +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return @@ -174,7 +175,7 @@ do_test malloc5-3.2 { } {1 2 3 4 5 6 7 8 9 10 11 12} db2 close -sqlite_malloc_outstanding -clearmaxbytes +puts "Highwater mark: [sqlite3_memory_highwater]" # The following two test cases each execute a transaction in which # 10000 rows are inserted into table abc. The first test case is used @@ -198,22 +199,22 @@ do_test malloc5-4.1 { execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');" } execsql {COMMIT;} - set ::nMaxBytes [sqlite_malloc_outstanding -maxbytes] - if {$::nMaxBytes==""} {set ::nMaxBytes 1000001} - expr $::nMaxBytes > 1000000 + set nMaxBytes [sqlite3_memory_highwater 1] + puts -nonewline " (Highwater mark: $nMaxBytes) " + expr $nMaxBytes > 1000000 } {1} do_test malloc5-4.2 { sqlite3_release_memory - sqlite_malloc_outstanding -clearmaxbytes sqlite3_soft_heap_limit 100000 + sqlite3_memory_highwater 1 execsql {BEGIN;} for {set i 0} {$i < 10000} {incr i} { execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');" } execsql {COMMIT;} - set ::nMaxBytes [sqlite_malloc_outstanding -maxbytes] - if {$::nMaxBytes==""} {set ::nMaxBytes 0} - expr $::nMaxBytes <= 100000 + set nMaxBytes [sqlite3_memory_highwater 1] + puts -nonewline " (Highwater mark: $nMaxBytes) " + expr $nMaxBytes <= 100000 } {1} do_test malloc5-4.3 { # Check that the content of table abc is at least roughly as expected. diff --git a/test/malloc6.test b/test/malloc6.test index 30fe00d61..1ce992796 100644 --- a/test/malloc6.test +++ b/test/malloc6.test @@ -9,122 +9,24 @@ # #*********************************************************************** # This file attempts to check the library in an out-of-memory situation. -# When compiled with -DSQLITE_DEBUG=1, the SQLite library accepts a special -# command (sqlite_malloc_fail N) which causes the N-th malloc to fail. This -# special feature is used to see what happens in the library if a malloc -# were to really fail due to an out-of-memory situation. # -# $Id: malloc6.test,v 1.1 2006/06/26 12:50:09 drh Exp $ +# $Id: malloc6.test,v 1.2 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } +source $testdir/malloc_common.tcl -# Usage: do_malloc_test <test number> <options...> -# -# The first argument, <test number>, is an integer used to name the -# tests executed by this proc. Options are as follows: -# -# -tclprep TCL script to run to prepare test. -# -sqlprep SQL script to run to prepare test. -# -tclbody TCL script to run with malloc failure simulation. -# -sqlbody TCL script to run with malloc failure simulation. -# -cleanup TCL script to run after the test. -# -# This command runs a series of tests to verify SQLite's ability -# to handle an out-of-memory condition gracefully. It is assumed -# that if this condition occurs a malloc() call will return a -# NULL pointer. Linux, for example, doesn't do that by default. See -# the "BUGS" section of malloc(3). -# -# Each iteration of a loop, the TCL commands in any argument passed -# to the -tclbody switch, followed by the SQL commands in any argument -# passed to the -sqlbody switch are executed. Each iteration the -# Nth call to sqliteMalloc() is made to fail, where N is increased -# each time the loop runs starting from 1. When all commands execute -# successfully, the loop ends. -# -proc do_malloc_test {tn args} { - array unset ::mallocopts - array set ::mallocopts $args - - set ::go 1 - for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { - do_test malloc6-$tn.$::n { - - # Remove all traces of database files test.db and test2.db from the files - # system. Then open (empty database) "test.db" with the handle [db]. - # - sqlite_malloc_fail 0 - catch {db close} - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - catch {file delete -force test2.db} - catch {file delete -force test2.db-journal} - catch {sqlite3 db test.db} - set ::DB [sqlite3_connection_pointer db] - - # Execute any -tclprep and -sqlprep scripts. - # - if {[info exists ::mallocopts(-tclprep)]} { - eval $::mallocopts(-tclprep) - } - if {[info exists ::mallocopts(-sqlprep)]} { - execsql $::mallocopts(-sqlprep) - } - - # Now set the ${::n}th malloc() to fail and execute the -tclbody and - # -sqlbody scripts. - # - sqlite_malloc_fail $::n - set ::mallocbody {} - if {[info exists ::mallocopts(-tclbody)]} { - append ::mallocbody "$::mallocopts(-tclbody)\n" - } - if {[info exists ::mallocopts(-sqlbody)]} { - append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" - } - set v [catch $::mallocbody msg] - - # If the test fails (if $v!=0) and the database connection actually - # exists, make sure the failure code is SQLITE_NOMEM. - if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] - && [db errorcode]!=7} { - set v 999 - } - - set leftover [lindex [sqlite_malloc_stat] 2] - if {$leftover>0} { - if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} - set ::go 0 - if {$v} { - puts "\nError message returned: $msg" - } else { - set v {1 1} - } - } else { - set v2 [expr {$msg=="" || $msg=="out of memory"}] - if {!$v2} {puts "\nError message returned: $msg"} - lappend v $v2 - } - } {1 1} - - if {[info exists ::mallocopts(-cleanup)]} { - catch [list uplevel #0 $::mallocopts(-cleanup)] msg - } - } - unset ::mallocopts -} set sqlite_os_trace 0 -do_malloc_test 1 -tclprep { +do_malloc_test malloc6-1 -tclprep { db close } -tclbody { if {[catch {sqlite3 db test.db}]} { @@ -149,5 +51,4 @@ do_test malloc6-1.X { set sqlite_open_file_count } {0} -sqlite_malloc_fail 0 finish_test diff --git a/test/malloc7.test b/test/malloc7.test index fc8b3abbd..e761d1996 100644 --- a/test/malloc7.test +++ b/test/malloc7.test @@ -11,130 +11,33 @@ # This file contains additional out-of-memory checks (see malloc.tcl) # added to expose a bug in out-of-memory handling for sqlite3_prepare16(). # -# $Id: malloc7.test,v 1.2 2006/07/26 14:57:30 drh Exp $ +# $Id: malloc7.test,v 1.3 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } +source $testdir/malloc_common.tcl -# Usage: do_malloc_test <test number> <options...> -# -# The first argument, <test number>, is an integer used to name the -# tests executed by this proc. Options are as follows: -# -# -tclprep TCL script to run to prepare test. -# -sqlprep SQL script to run to prepare test. -# -tclbody TCL script to run with malloc failure simulation. -# -sqlbody TCL script to run with malloc failure simulation. -# -cleanup TCL script to run after the test. -# -# This command runs a series of tests to verify SQLite's ability -# to handle an out-of-memory condition gracefully. It is assumed -# that if this condition occurs a malloc() call will return a -# NULL pointer. Linux, for example, doesn't do that by default. See -# the "BUGS" section of malloc(3). -# -# Each iteration of a loop, the TCL commands in any argument passed -# to the -tclbody switch, followed by the SQL commands in any argument -# passed to the -sqlbody switch are executed. Each iteration the -# Nth call to sqliteMalloc() is made to fail, where N is increased -# each time the loop runs starting from 1. When all commands execute -# successfully, the loop ends. -# -proc do_malloc_test {tn args} { - array unset ::mallocopts - array set ::mallocopts $args - - set ::go 1 - for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { - do_test malloc7-$tn.$::n { - - # Remove all traces of database files test.db and test2.db from the files - # system. Then open (empty database) "test.db" with the handle [db]. - # - sqlite_malloc_fail 0 - catch {db close} - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - catch {file delete -force test2.db} - catch {file delete -force test2.db-journal} - catch {sqlite3 db test.db} - set ::DB [sqlite3_connection_pointer db] - - # Execute any -tclprep and -sqlprep scripts. - # - if {[info exists ::mallocopts(-tclprep)]} { - eval $::mallocopts(-tclprep) - } - if {[info exists ::mallocopts(-sqlprep)]} { - execsql $::mallocopts(-sqlprep) - } - # Now set the ${::n}th malloc() to fail and execute the -tclbody and - # -sqlbody scripts. - # - sqlite_malloc_fail $::n - set ::mallocbody {} - if {[info exists ::mallocopts(-tclbody)]} { - append ::mallocbody "$::mallocopts(-tclbody)\n" - } - if {[info exists ::mallocopts(-sqlbody)]} { - append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" - } - set v [catch $::mallocbody msg] - - # If the test fails (if $v!=0) and the database connection actually - # exists, make sure the failure code is SQLITE_NOMEM. - if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] - && [db errorcode]!=7} { - set v 999 - } - - set leftover [lindex [sqlite_malloc_stat] 2] - if {$leftover>0} { - if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} - set ::go 0 - if {$v} { - puts "\nError message returned: $msg" - } else { - set v {1 1} - } - } else { - set v2 [expr {$msg=="" || $msg=="out of memory"}] - if {!$v2} {puts "\nError message returned: $msg"} - lappend v $v2 - } - } {1 1} - - if {[info exists ::mallocopts(-cleanup)]} { - catch [list uplevel #0 $::mallocopts(-cleanup)] msg - } - } - unset ::mallocopts -} - -db eval { +do_malloc_test malloc7-1 -sqlprep { CREATE TABLE t1(a,b,c,d); CREATE INDEX i1 ON t1(b,c); -} - -do_malloc_test 1 -tclbody { +} -tclbody { set sql16 [encoding convertto unicode "SELECT * FROM sqlite_master"] append sql16 "\00\00" set nbyte [string length $sql16] - set ::STMT [sqlite3_prepare16 $::DB $sql16 $nbyte DUMMY] + set ::STMT [sqlite3_prepare16 db $sql16 $nbyte DUMMY] sqlite3_finalize $::STMT } - # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} @@ -142,5 +45,4 @@ do_test malloc-99.X { } {0} puts open-file-count=$sqlite_open_file_count -sqlite_malloc_fail 0 finish_test diff --git a/test/malloc8.test b/test/malloc8.test index e493647c6..19753545b 100644 --- a/test/malloc8.test +++ b/test/malloc8.test @@ -11,107 +11,20 @@ # This file contains additional out-of-memory checks (see malloc.tcl) # added to expose a bug in out-of-memory handling for sqlite3_value_text() # -# $Id: malloc8.test,v 1.3 2007/05/07 19:31:17 drh Exp $ +# $Id: malloc8.test,v 1.4 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } -# Usage: do_malloc_test <test number> <options...> -# -# The first argument, <test number>, is an integer used to name the -# tests executed by this proc. Options are as follows: -# -# -tclprep TCL script to run to prepare test. -# -sqlprep SQL script to run to prepare test. -# -tclbody TCL script to run with malloc failure simulation. -# -sqlbody TCL script to run with malloc failure simulation. -# -cleanup TCL script to run after the test. -# -# This command runs a series of tests to verify SQLite's ability -# to handle an out-of-memory condition gracefully. It is assumed -# that if this condition occurs a malloc() call will return a -# NULL pointer. Linux, for example, doesn't do that by default. See -# the "BUGS" section of malloc(3). -# -# Each iteration of a loop, the TCL commands in any argument passed -# to the -tclbody switch, followed by the SQL commands in any argument -# passed to the -sqlbody switch are executed. Each iteration the -# Nth call to sqliteMalloc() is made to fail, where N is increased -# each time the loop runs starting from 1. When all commands execute -# successfully, the loop ends. -# -proc do_malloc_test {tn args} { - array unset ::mallocopts - array set ::mallocopts $args - - set ::go 1 - for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { - do_test malloc8-$tn.$::n { - - sqlite_malloc_fail 0 - catch {db close} - sqlite3 db test.db - set ::DB [sqlite3_connection_pointer db] - - # Execute any -tclprep and -sqlprep scripts. - # - if {[info exists ::mallocopts(-tclprep)]} { - eval $::mallocopts(-tclprep) - } - if {[info exists ::mallocopts(-sqlprep)]} { - execsql $::mallocopts(-sqlprep) - } - - # Now set the ${::n}th malloc() to fail and execute the -tclbody and - # -sqlbody scripts. - # - sqlite_malloc_fail $::n - set ::mallocbody {} - if {[info exists ::mallocopts(-tclbody)]} { - append ::mallocbody "$::mallocopts(-tclbody)\n" - } - if {[info exists ::mallocopts(-sqlbody)]} { - append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" - } - set v [catch $::mallocbody msg] - - # If the test fails (if $v!=0) and the database connection actually - # exists, make sure the failure code is SQLITE_NOMEM. - if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] - && [db errorcode]!=7} { - set v 999 - } - - set leftover [lindex [sqlite_malloc_stat] 2] - if {$leftover>0} { - if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} - set ::go 0 - if {$v} { - puts "\nError message returned: $msg" - } else { - set v {1 1} - } - } else { - set v2 [expr {$msg=="" || $msg=="out of memory"}] - if {!$v2} {puts "\nError message returned: $msg"} - lappend v $v2 - } - } {1 1} - - if {[info exists ::mallocopts(-cleanup)]} { - catch [list uplevel #0 $::mallocopts(-cleanup)] msg - } - } - unset ::mallocopts -} +source $testdir/malloc_common.tcl # The setup is a database with UTF-16 encoding that contains a single # large string. We will be running lots of queries against this @@ -120,34 +33,54 @@ proc do_malloc_test {tn args} { # to fail and for sqlite3_value_text() to return 0 even though # sqlite3_value_type() returns SQLITE_TEXT. # -db close -file delete -force test.db test.db-journal -sqlite3 db test.db -db eval { + +do_malloc_test malloc8-1 -sqlprep { PRAGMA encoding='UTF-16'; CREATE TABLE t1(a); INSERT INTO t1 VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'); -} - - -do_malloc_test 1 -sqlbody { +} -sqlbody { SELECT lower(a), upper(a), quote(a), trim(a), trim('x',a) FROM t1; } -do_malloc_test 2 -sqlbody { +do_malloc_test malloc8-2 -sqlprep { + PRAGMA encoding='UTF-16'; + CREATE TABLE t1(a); + INSERT INTO t1 + VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'); +} -sqlbody { SELECT replace(a,'x','y'), replace('x',a,'y'), replace('x','y',a) FROM t1; } -do_malloc_test 3 -sqlbody { +do_malloc_test malloc8-3 -sqlprep { + PRAGMA encoding='UTF-16'; + CREATE TABLE t1(a); + INSERT INTO t1 + VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'); +} -sqlbody { SELECT length(a), substr(a, 4, 4) FROM t1; } -do_malloc_test 4 -sqlbody { +do_malloc_test malloc8-4 -sqlprep { + PRAGMA encoding='UTF-16'; + CREATE TABLE t1(a); + INSERT INTO t1 + VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'); +} -sqlbody { SELECT julianday(a,a) FROM t1; } -do_malloc_test 5 -sqlbody { +do_malloc_test malloc8-5 -sqlprep { + PRAGMA encoding='UTF-16'; + CREATE TABLE t1(a); + INSERT INTO t1 + VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'); +} -sqlbody { SELECT 1 FROM t1 WHERE a LIKE 'hello' ESCAPE NULL; } -do_malloc_test 6 -sqlbody { +do_malloc_test malloc8-6 -sqlprep { + PRAGMA encoding='UTF-16'; + CREATE TABLE t1(a); + INSERT INTO t1 + VALUES('0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'); +} -sqlbody { SELECT hex(randomblob(100)); } @@ -157,5 +90,4 @@ do_test malloc-99.X { set sqlite_open_file_count } {0} -sqlite_malloc_fail 0 finish_test diff --git a/test/malloc9.test b/test/malloc9.test index 5df82e4e1..e5e734a22 100644 --- a/test/malloc9.test +++ b/test/malloc9.test @@ -11,110 +11,20 @@ # This file contains additional out-of-memory checks (see malloc.tcl) # added to expose a bug in out-of-memory handling for sqlite3_prepare(). # -# $Id: malloc9.test,v 1.1 2007/04/30 21:39:16 drh Exp $ +# $Id: malloc9.test,v 1.2 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } -# Usage: do_malloc_test <test number> <options...> -# -# The first argument, <test number>, is an integer used to name the -# tests executed by this proc. Options are as follows: -# -# -tclprep TCL script to run to prepare test. -# -sqlprep SQL script to run to prepare test. -# -tclbody TCL script to run with malloc failure simulation. -# -sqlbody TCL script to run with malloc failure simulation. -# -cleanup TCL script to run after the test. -# -# This command runs a series of tests to verify SQLite's ability -# to handle an out-of-memory condition gracefully. It is assumed -# that if this condition occurs a malloc() call will return a -# NULL pointer. Linux, for example, doesn't do that by default. See -# the "BUGS" section of malloc(3). -# -# Each iteration of a loop, the TCL commands in any argument passed -# to the -tclbody switch, followed by the SQL commands in any argument -# passed to the -sqlbody switch are executed. Each iteration the -# Nth call to sqliteMalloc() is made to fail, where N is increased -# each time the loop runs starting from 1. When all commands execute -# successfully, the loop ends. -# -proc do_malloc_test {tn args} { - array unset ::mallocopts - array set ::mallocopts $args - - set ::go 1 - for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { - do_test malloc9-$tn.$::n { - - sqlite_malloc_fail 0 - catch {db close} - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - sqlite3 db test.db - set ::DB [sqlite3_connection_pointer db] - - # Execute any -tclprep and -sqlprep scripts. - # - if {[info exists ::mallocopts(-tclprep)]} { - eval $::mallocopts(-tclprep) - } - if {[info exists ::mallocopts(-sqlprep)]} { - execsql $::mallocopts(-sqlprep) - } - - # Now set the ${::n}th malloc() to fail and execute the -tclbody and - # -sqlbody scripts. - # - sqlite_malloc_fail $::n - set ::mallocbody {} - if {[info exists ::mallocopts(-tclbody)]} { - append ::mallocbody "$::mallocopts(-tclbody)\n" - } - if {[info exists ::mallocopts(-sqlbody)]} { - append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" - } - set v [catch $::mallocbody msg] - - # If the test fails (if $v!=0) and the database connection actually - # exists, make sure the failure code is SQLITE_NOMEM. - if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] - && [db errorcode]!=7} { - set v 999 - } - - set leftover [lindex [sqlite_malloc_stat] 2] - if {$leftover>0} { - if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} - set ::go 0 - if {$v} { - puts "\nError message returned: $msg" - } else { - set v {1 1} - } - } else { - set v2 [expr {$msg=="" || [regexp {out of memory} $msg]}] - if {!$v2} {puts "\nError message returned: $msg"} - lappend v $v2 - } - } {1 1} - - if {[info exists ::mallocopts(-cleanup)]} { - catch [list uplevel #0 $::mallocopts(-cleanup)] msg - } - } - unset ::mallocopts -} - +source $testdir/malloc_common.tcl do_malloc_test 1 -tclprep { set sql {CREATE TABLE t1(x)} @@ -138,5 +48,4 @@ do_test malloc-99.X { set sqlite_open_file_count } {0} -sqlite_malloc_fail 0 finish_test diff --git a/test/mallocA.test b/test/mallocA.test index be2b81661..84e96b4ca 100644 --- a/test/mallocA.test +++ b/test/mallocA.test @@ -10,109 +10,20 @@ #*********************************************************************** # This file contains additional out-of-memory checks (see malloc.tcl). # -# $Id: mallocA.test,v 1.2 2007/05/12 15:00:15 drh Exp $ +# $Id: mallocA.test,v 1.3 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } -# Usage: do_malloc_test <test number> <options...> -# -# The first argument, <test number>, is an integer used to name the -# tests executed by this proc. Options are as follows: -# -# -tclprep TCL script to run to prepare test. -# -sqlprep SQL script to run to prepare test. -# -tclbody TCL script to run with malloc failure simulation. -# -sqlbody TCL script to run with malloc failure simulation. -# -cleanup TCL script to run after the test. -# -# This command runs a series of tests to verify SQLite's ability -# to handle an out-of-memory condition gracefully. It is assumed -# that if this condition occurs a malloc() call will return a -# NULL pointer. Linux, for example, doesn't do that by default. See -# the "BUGS" section of malloc(3). -# -# Each iteration of a loop, the TCL commands in any argument passed -# to the -tclbody switch, followed by the SQL commands in any argument -# passed to the -sqlbody switch are executed. Each iteration the -# Nth call to sqliteMalloc() is made to fail, where N is increased -# each time the loop runs starting from 1. When all commands execute -# successfully, the loop ends. -# -proc do_malloc_test {tn args} { - array unset ::mallocopts - array set ::mallocopts $args - - set ::go 1 - for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { - do_test mallocA-$tn.$::n { - - sqlite_malloc_fail 0 - catch {db close} - catch {file delete -force test.db test.db-journal} - catch {file copy test.db.bu test.db} - sqlite3 db test.db - set ::DB [sqlite3_connection_pointer db] - - # Execute any -tclprep and -sqlprep scripts. - # - if {[info exists ::mallocopts(-tclprep)]} { - eval $::mallocopts(-tclprep) - } - if {[info exists ::mallocopts(-sqlprep)]} { - execsql $::mallocopts(-sqlprep) - } - - # Now set the ${::n}th malloc() to fail and execute the -tclbody and - # -sqlbody scripts. - # - sqlite_malloc_fail $::n - set ::mallocbody {} - if {[info exists ::mallocopts(-tclbody)]} { - append ::mallocbody "$::mallocopts(-tclbody)\n" - } - if {[info exists ::mallocopts(-sqlbody)]} { - append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" - } - set v [catch $::mallocbody msg] - - # If the test fails (if $v!=0) and the database connection actually - # exists, make sure the failure code is SQLITE_NOMEM. - if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] - && [db errorcode]!=7} { - set v 999 - } - - set leftover [lindex [sqlite_malloc_stat] 2] - if {$leftover>0} { - if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} - set ::go 0 - if {$v} { - puts "\nError message returned: $msg" - } else { - set v {1 1} - } - } else { - set v2 [expr {$msg=="" || [regexp {out of memory} $msg]}] - if {!$v2} {puts "\nError message returned: $msg"} - lappend v $v2 - } - } {1 1} - - if {[info exists ::mallocopts(-cleanup)]} { - catch [list uplevel #0 $::mallocopts(-cleanup)] msg - } - } - unset ::mallocopts -} +source $testdir/malloc_common.tcl # Construct a test database # @@ -128,22 +39,21 @@ db eval { } db close file copy test.db test.db.bu -sqlite3 db test.db -do_malloc_test 1 -sqlbody { +do_malloc_test 1 -testdb test.db.bu -sqlbody { ANALYZE } -do_malloc_test 2 -sqlbody { +do_malloc_test 2 -testdb test.db.bu -sqlbody { REINDEX; } -do_malloc_test 3 -sqlbody { +do_malloc_test 3 -testdb test.db.bu -sqlbody { REINDEX t1; } -do_malloc_test 4 -sqlbody { +do_malloc_test 4 -testdb test.db.bu -sqlbody { REINDEX main.t1; } -do_malloc_test 5 -sqlbody { +do_malloc_test 5 -testdb test.db.bu -sqlbody { REINDEX nocase; } @@ -154,5 +64,4 @@ do_test malloc-99.X { } {0} file delete -force test.db.bu -sqlite_malloc_fail 0 finish_test diff --git a/test/mallocB.test b/test/mallocB.test index 80dd2dd12..2cef24e01 100644 --- a/test/mallocB.test +++ b/test/mallocB.test @@ -13,7 +13,7 @@ # that they have little in common. # # -# $Id: mallocB.test,v 1.3 2007/07/26 06:50:06 danielk1977 Exp $ +# $Id: mallocB.test,v 1.4 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -21,11 +21,12 @@ source $testdir/malloc_common.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { +ifcapable !memdebug { puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } +source $testdir/malloc_common.tcl do_malloc_test mallocB-1 -sqlbody {SELECT - 456} do_malloc_test mallocB-2 -sqlbody {SELECT - 456.1} @@ -41,5 +42,4 @@ do_malloc_test mallocB-5 -sqlbody {SELECT * FROM (SELECT 1) GROUP BY 1;} # do_malloc_test mallocB-6 -sqlbody { SELECT test_auxdata('hello world'); } -sqlite_malloc_fail 0 finish_test diff --git a/test/mallocC.test b/test/mallocC.test index 175d451b8..f10c223a4 100644 --- a/test/mallocC.test +++ b/test/mallocC.test @@ -12,17 +12,17 @@ # This file tests aspects of the malloc failure while parsing # CREATE TABLE statements in auto_vacuum mode. # -# $Id: mallocC.test,v 1.2 2007/08/13 12:58:18 drh Exp $ +# $Id: mallocC.test,v 1.3 2007/08/22 22:04:37 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # -if {[info command sqlite_malloc_stat]==""} { - puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG=1" - finish_test - return +ifcapable !memdebug { + puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." + finish_test + return } # Generate a checksum based on the contents of the database. If the @@ -61,7 +61,7 @@ proc do_mallocC_test {tn args} { # Run the SQL. Malloc number $::n is set to fail. A malloc() failure # may or may not be reported. - sqlite_malloc_fail $::n + sqlite3_memdebug_fail $::n 1 do_test mallocC-$tn.$::n.1 { set res [catchsql [string trim $::mallocopts(-sql)]] set rc [expr { @@ -76,8 +76,8 @@ proc do_mallocC_test {tn args} { # If $::n is greater than the number of malloc() calls required to # execute the SQL, then this test is finished. Break out of the loop. - if {[lindex [sqlite_malloc_stat] 2]>0} { - sqlite_malloc_fail -1 + set nFail [sqlite3_memdebug_fail -1 -1] + if {$nFail==0} { break } diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index 98e8b4892..c49f5ac61 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -48,6 +48,9 @@ proc do_malloc_test {tn args} { catch {file delete -force test.db-journal} catch {file delete -force test2.db} catch {file delete -force test2.db-journal} + if {[info exists ::mallocopts(-testdb)]} { + file copy $::mallocopts(-testdb) test.db + } catch {sqlite3 db test.db} # Execute any -tclprep and -sqlprep scripts. diff --git a/test/tester.tcl b/test/tester.tcl index 8b38beb3d..55c2a1c41 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -11,7 +11,7 @@ # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.85 2007/08/22 20:18:22 drh Exp $ +# $Id: tester.tcl,v 1.86 2007/08/22 22:04:37 drh Exp $ # Make sure tclsqlite3 was compiled correctly. Abort now with an # error message if not. @@ -192,9 +192,6 @@ proc finalize_testing {} { catch {db2 close} catch {db3 close} - catch { - pp_check_for_leaks - } sqlite3 db {} # sqlite3_clear_tsd_memdebug db close @@ -571,63 +568,6 @@ proc copy_file {from to} { } } -# This command checks for outstanding calls to sqlite3_malloc() -# A list is returned with one entry for each outstanding -# malloc. Each list entry is itself a list of 5 items, as follows: -# -# { <number-bytes> <file-name> <line-number> <test-case> <stack-dump> } -# -proc check_for_leaks {} { - set ret [list] - set cnt 0 - foreach alloc [sqlite_malloc_outstanding] { - foreach {nBytes file iLine userstring backtrace} $alloc {} - set stack [list] - set skip 0 - - # The first command in this block will probably fail on windows. This - # means there will be no stack dump available. - if {$cnt < 25 && $backtrace!=""} { - catch { - set stuff [eval "exec addr2line -e ./testfixture -f $backtrace"] - foreach {func line} $stuff { - if {$func != "??" || $line != "??:0"} { - regexp {.*/(.*)} $line dummy line - lappend stack "${func}() $line" - } else { - if {[lindex $stack end] != "..."} { - lappend stack "..." - } - } - } - } - incr cnt - } - - if {!$skip} { - lappend ret [list $nBytes $file $iLine $userstring $stack] - } - } - return $ret -} - -# Pretty print a report based on the return value of [check_for_leaks] to -# stdout. -proc pp_check_for_leaks {} { - set l [check_for_leaks] - set n 0 - foreach leak $l { - foreach {nBytes file iLine userstring stack} $leak {} - puts "$nBytes bytes leaked at $file:$iLine ($userstring)" - foreach frame $stack { - puts " $frame" - } - incr n $nBytes - } - puts "Memory leaked: $n bytes in [llength $l] allocations" - puts "" -} - # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set # to non-zero, then set the global variable $AUTOVACUUM to 1. set AUTOVACUUM $sqlite_options(default_autovacuum) |