diff options
-rw-r--r-- | manifest | 42 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/mem2.c | 11 | ||||
-rw-r--r-- | src/pager.c | 19 | ||||
-rw-r--r-- | src/test_malloc.c | 34 | ||||
-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 |
18 files changed, 216 insertions, 677 deletions
@@ -1,5 +1,5 @@ -C The\smalloc.test\sscript\snow\spasses\sall\stests\swith\sno\serrors.\s(CVS\s4271) -D 2007-08-22T20:18:22 +C All\sof\sthe\smalloc\stest\scases\srun.\s\sStill\sseeing\sfailures\sin\smalloc4.test.\s(CVS\s4272) +D 2007-08-22T22:04:37 F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -102,7 +102,7 @@ F src/main.c 527f27c74d22d83713abbd1550fd5a4ecce89aca F src/malloc.c 8078d4c3f9217c0bb018e432d8655c14996bb107 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/mem1.c 7b023d45dd71944414db469c742457239e24d74d -F src/mem2.c b707e02fec2cf4d6fce8427d640e90d5003afe9e +F src/mem2.c 28a0d9306378f97e5cddb7863cb3893d40d1f885 F src/mutex.c 9cf641f556a4119ef90ed41b82f2d5647f81686e F src/os.c d8f029317c95dcd2887b9f0f154281cdfbd303ad F src/os.h 399c89cafa93b9ef35c3dc70f77644d10936b535 @@ -115,7 +115,7 @@ F src/os_unix.c 3e1ce27aa8364f92881a285820ffa414539a6b1b F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c 29c0e19c1072679a4c7818c49fab2f35d2ad7747 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 029a441236e9f504e25a3e2d2944afeae48c297c +F src/pager.c 54087a81a44e38e30cf8bfed41a73acc9ece84a8 F src/pager.h 53087c6fb9db01aed17c7fd044662a27507e89b8 F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590 F src/pragma.c 9b989506a1b7c8aecd6befb8235e2f57a4aba7e5 @@ -146,7 +146,7 @@ F src/test_btree.c c1308ba0b88ab577fa56c9e493a09829dfcded9c F src/test_config.c f0b911bb615d93a192647e76910dce65cbbcf3ad F src/test_hexio.c 82916f918687502658f02533b519c38cb180db6d F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 -F src/test_malloc.c d9ba6be85f9c4a439b19f6e0a72d91c369d72c63 +F src/test_malloc.c 1e24e6bf8dfff1886b57b353911493e7025c2158 F src/test_md5.c 34599caee5b1c73dcf86ca31f55846fab8c19ef7 F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f F src/test_server.c 319f6b1a99bab5f7149387442243d6e65a8ab4eb @@ -339,18 +339,18 @@ F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 F test/lock4.test 49e22396b9be6e047b3d35469f233be79153c9d5 F test/main.test e7212ce1023957c7209778cc87fa932bd79ba89a F test/malloc.test dbfaedfca734283182db18a64416cf037c33648f -F test/malloc2.test 4ed7d719542c4570dec9c2ebe2bbdf3a9f3b0d05 -F test/malloc3.test e965954b6f808876a63d3101fd70370320b509a7 -F test/malloc4.test 59cd02f71b363302a04c4e77b97c0a1572eaa210 -F test/malloc5.test 90b1f1ce9f835e6d14fb01be1452169b21d12818 -F test/malloc6.test 025ae0b78542e0ddd000d23f79d93e9be9ba0f15 -F test/malloc7.test 1cf52834509eac7ebeb92105dacd4669f9ca9869 -F test/malloc8.test e4054ca2a87ab1d42255bec009b177ba20b5a487 -F test/malloc9.test 8381041fd89c31fba60c8a1a1c776bb022108572 -F test/mallocA.test 525674e6e0775a9bf85a33f1da1c6bbddc712c30 -F test/mallocB.test 5d4a3dc4931a8c13ef3723c4934af23ff9d60d71 -F test/mallocC.test e470e03fe8b28d79f0a5123601a9653331cc7226 -F test/malloc_common.tcl 7b59db5f0617678f4e5af3a7b3715a1dacd1b8e2 +F test/malloc2.test 96dfa6318d3b7bcd41d4fe7e24d35196d465bf58 +F test/malloc3.test 65d323508c7c4e1fb5569d03a11070b0259ad2fe +F test/malloc4.test 3f4857ca83168c00900221681fc76de04394968a +F test/malloc5.test 6f7b96f1bea181d789a7140fd3fabfb0e333d8f5 +F test/malloc6.test 3733b9bd4e039c3239f869c40edbb88172025e2e +F test/malloc7.test dd66d8f82916becf1d29b6640e4f4855485570f8 +F test/malloc8.test 5ff95278bc73e815e295971afcdd175f6ba19258 +F test/malloc9.test fb99833476bc1a9b0b15573b9a56ae13af843ef9 +F test/mallocA.test f49b8df5e1d2a090830ef5a5f94174c3c930234b +F test/mallocB.test 56fd615f3fea97180132a89dd1dd2068852ef6a0 +F test/mallocC.test b6b83dea1c3820a70d50b0378481b71bda44bcb3 +F test/malloc_common.tcl 4f07ce6b4a542cc7052e26543406bca439a863f5 F test/manydb.test 8de36b8d33aab5ef295b11d9e95310aeded31af8 F test/memdb.test a67bda4ff90a38f2b19f6c7f95aa7289e051d893 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217 @@ -412,7 +412,7 @@ F test/table.test dbdfd06aef054ad5aed8e57a782137d57d5c5528 F test/tableapi.test 036575a98dcce7c92e9f39056839bbad8a715412 F test/tclsqlite.test 593f3b30221e85786965d9e5670ae4f96b4e4159 F test/temptable.test c36f3e5a94507abb64f7ba23deeb4e1a8a8c3821 -F test/tester.tcl e72b0b8e1b1d9cf20bc641793a3d3c5442a5bbb3 +F test/tester.tcl c9cd05b488392bde9e7e8044d988943a4a52f1fe F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35 F test/thread2.test 6d7b30102d600f51b4055ee3a5a19228799049fb F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b @@ -559,7 +559,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P b6399dff1370449912391cc5925bdc468b5dade0 -R 3ea0ebd7e3bb257a718fe4ade9660d28 +P db818430e9ea4ef4a4af575784009d5acae785a3 +R 5826e29b4eff86308f2e435b216e5a67 U drh -Z 59e51dd8c4f548815477ba78b815fe4b +Z 50c7b8ba17910d7b90bf428d2ab32765 diff --git a/manifest.uuid b/manifest.uuid index 75e49e691..7131fcb4f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db818430e9ea4ef4a4af575784009d5acae785a3
\ No newline at end of file +205d0b881d541db65837ce6cf44d58d607635bc2
\ No newline at end of file diff --git a/src/mem2.c b/src/mem2.c index 57a610225..d9653ee81 100644 --- a/src/mem2.c +++ b/src/mem2.c @@ -12,7 +12,7 @@ ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.6 2007/08/22 20:18:22 drh Exp $ +** $Id: mem2.c,v 1.7 2007/08/22 22:04:37 drh Exp $ */ /* @@ -455,6 +455,15 @@ int sqlite3_memdebug_fail(int iFail, int iRepeat){ } /* +** This routine returns the number of successful mallocs remaining until +** the next simulated malloc failure. -1 is returned if no simulated +** failure is currently scheduled. +*/ +int sqlite3_memdebug_pending(void){ + return mem.iFail-1; +} + +/* ** The following two routines are used to assert that no memory ** allocations occur between one call and the next. The use of ** these routines does not change the computed results in any way. diff --git a/src/pager.c b/src/pager.c index b0fbcffb5..b261c7fc3 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.367 2007/08/22 18:54:33 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.368 2007/08/22 22:04:37 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -538,7 +538,9 @@ static int pageInStatement(PgHdr *pPg){ static void pager_resize_hash_table(Pager *pPager, int N){ PgHdr **aHash, *pPg; assert( N>0 && (N&(N-1))==0 ); + pagerLeave(pPager); aHash = sqlite3MallocZero( sizeof(aHash[0])*N ); + pagerEnter(pPager); if( aHash==0 ){ /* Failure to rehash is not an error. It is only a performance hit. */ return; @@ -2873,7 +2875,7 @@ int sqlite3PagerReleaseMemory(int nReq){ Pager *pPager = sqlite3PagerList; for( ; pPager && (nReq<0 || nReleased<nReq); pPager=pPager->pNext){ PgHdr *pPg; - int rc; + int rc = SQLITE_OK; /* In-memory databases should not appear on the pager list */ assert( !MEMDB ); @@ -2885,7 +2887,10 @@ int sqlite3PagerReleaseMemory(int nReq){ ** calling fsync() if this is the first iteration of the outermost ** loop). */ - while( SQLITE_OK==(rc = pager_recycle(pPager, i, &pPg)) && pPg) { + while( (nReq<0 || nReleased<nReq) && + SQLITE_OK==(rc = pager_recycle(pPager, i, &pPg)) && + pPg + ) { /* We've found a page to free. At this point the page has been ** removed from the page hash-table, free-list and synced-list ** (pFirstSynced). It is still in the all pages (pAll) list. @@ -3163,9 +3168,11 @@ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ goto pager_allocate_out; } } + pagerLeave(pPager); pPg = sqlite3_malloc( sizeof(*pPg) + pPager->pageSize + sizeof(u32) + pPager->nExtra + MEMDB*sizeof(PgHistory) ); + pagerEnter(pPager); if( pPg==0 ){ rc = SQLITE_NOMEM; goto pager_allocate_out; @@ -3486,7 +3493,9 @@ static int pager_open_journal(Pager *pPager){ assert( pPager->useJournal ); assert( pPager->aInJournal==0 ); sqlite3PagerPagecount(pPager); + pagerLeave(pPager); pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pagerEnter(pPager); if( pPager->aInJournal==0 ){ rc = SQLITE_NOMEM; goto failed_to_open_journal; @@ -3610,7 +3619,9 @@ int sqlite3PagerBegin(DbPage *pPg, int exFlag){ assert( pPager->origDbSize==0 ); assert( pPager->aInJournal==0 ); sqlite3PagerPagecount(pPager); + pagerLeave(pPager); pPager->aInJournal = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pagerEnter(pPager); if( !pPager->aInJournal ){ rc = SQLITE_NOMEM; }else{ @@ -4439,7 +4450,9 @@ static int pagerStmtBegin(Pager *pPager){ return SQLITE_OK; } assert( pPager->journalOpen ); + pagerLeave(pPager); pPager->aInStmt = sqlite3MallocZero( pPager->dbSize/8 + 1 ); + pagerEnter(pPager); if( pPager->aInStmt==0 ){ /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */ return SQLITE_NOMEM; diff --git a/src/test_malloc.c b/src/test_malloc.c index 6560fc9dd..478c6c5f8 100644 --- a/src/test_malloc.c +++ b/src/test_malloc.c @@ -13,7 +13,7 @@ ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. ** -** $Id: test_malloc.c,v 1.2 2007/08/15 20:41:29 drh Exp $ +** $Id: test_malloc.c,v 1.3 2007/08/22 22:04:37 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -228,7 +228,7 @@ static int test_memdebug_dump( /* -** Usage: sqlite3_memdebug_fail COUNTER REPEAT +** Usage: sqlite3_memdebug_fail COUNTER ?REPEAT? ** ** Arrange for a simulated malloc() failure after COUNTER successes. ** If REPEAT is 1 then all subsequent malloc()s fail. If REPEAT is @@ -249,12 +249,16 @@ static int test_memdebug_fail( int iFail; int iRepeat; int nFail = 0; - if( objc!=3 ){ - Tcl_WrongNumArgs(interp, 1, objv, "COUNTER REPEAT"); + if( objc!=3 && objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "COUNTER ?REPEAT?"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[1], &iFail) ) return TCL_ERROR; - if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR; + if( objc==3 ){ + if( Tcl_GetIntFromObj(interp, objv[2], &iRepeat) ) return TCL_ERROR; + }else{ + iRepeat = -1; + } #ifdef SQLITE_MEMDEBUG { extern int sqlite3_memdebug_fail(int,int); @@ -267,6 +271,25 @@ static int test_memdebug_fail( /* +** Usage: sqlite3_memdebug_pending +** +** Return the number of successful mallocs remaining before the +** next simulated failure. Return -1 if no simulated failure is +** currently scheduled. +*/ +static int test_memdebug_pending( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + extern int sqlite3_memdebug_pending(void); + Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_memdebug_pending())); + return TCL_OK; +} + + +/* ** Register commands with the TCL interpreter. */ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ @@ -282,6 +305,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ { "sqlite3_memdebug_backtrace", test_memdebug_backtrace }, { "sqlite3_memdebug_dump", test_memdebug_dump }, { "sqlite3_memdebug_fail", test_memdebug_fail }, + { "sqlite3_memdebug_pending", test_memdebug_pending }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 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) |