diff --git a/manifest b/manifest index 8ce04374f3..287708ef0e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Documentation\supdates\sand\schanges\sthe\spublish.sh\sscript.\s(CVS\s1602) -D 2004-06-16T03:02:01 +C Fix\stwo\smore\smemory\sleaks.\s(CVS\s1603) +D 2004-06-16T07:45:24 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -48,7 +48,7 @@ F src/os_unix.c 8832c78dd95c115b1690054354d90321a791950d F src/os_unix.h 1cd6133cf66dea704b8646b70b2dfdcbdd9b3738 F src/os_win.c 337e973ee77797aaab4787e3477a5945fcd97266 F src/os_win.h 004eec47b1780fcaf07420ddc2072294b698d48c -F src/pager.c 8e26112df058f73e718938ed07bdbf10ab942c0f +F src/pager.c 48356cb434928994ce3c0aac2a6d95e80722c7b3 F src/pager.h bc58d32a9dee464f7268fb68652c130a4216e438 F src/parse.y 097438674976355a10cf177bd97326c548820b86 F src/pragma.c be8ed53611971f8c93f66cd31129af89e6d58997 @@ -69,13 +69,13 @@ F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b F src/trigger.c 3ff6f24e5273767117126b712eaae24c3d6466aa F src/update.c 6133c876aa126e1771cda165fd992bb0d2f8eb38 F src/utf.c e16737b3fc4201bf7ce9bd8ced5250596aa31b76 -F src/util.c 90375fa253137562d536ccdd40b297f0fd7413fc +F src/util.c 6e93dad9a17b34f37fc270ba871b224240168bf0 F src/vacuum.c f9561c8095407a970af4e6a304b77c4083433d3e F src/vdbe.c 208705994c0b3b160cb941a5a410838bd5559cf9 F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde F src/vdbeInt.h 4e636b1b6c18d1d85b085fe0e5a19d45ad85f382 F src/vdbeapi.c ee350b552fc4c1c695b760f914f69e9c5556e829 -F src/vdbeaux.c 3476058d13de206cc79cd7015c73e2bb4f37776e +F src/vdbeaux.c dc0e7d3bdf3b6f322448b4bee29fe5bec656b4d4 F src/vdbemem.c 1e7df5ed53bc05433c7d3fb28899cf2c82bd16ac F src/where.c 7fee7aeb9278f27324f228c55ab453b5f183b486 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 @@ -177,6 +177,7 @@ F tool/lemon.c db6a3bfaf3388c0f7aea3adb5e05acddcd427016 F tool/lempar.c 0b5e7a58634e0d448929b8e85f7981c2aa708d57 F tool/memleak.awk b744b6109566206c746d826f6ecdba34662216bc F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 +F tool/memleak3.tcl 336eb50b0849dbf99b1d5462d9c37291b01b2b43 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816 @@ -223,7 +224,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 07b90f3690768e852384fbbde0ba59e69e24d1da -R 3acf8389b7928b0e6bed5f904140c093 -U drh -Z d8b4e54d3b0adc4de12efd128b05998c +P e9a77f8972128550f6ff98dcf854eb7680eaee8b +R 925b12cad91290c34145812d35712b79 +U danielk1977 +Z 728cd56f54fcbd121f4ed570a3126bce diff --git a/manifest.uuid b/manifest.uuid index 38bdd5ba65..e57d2d6822 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e9a77f8972128550f6ff98dcf854eb7680eaee8b \ No newline at end of file +98b48704a1ce983677cdb269c24f7bca4ed606f7 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 383c481f77..1a6319bd40 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.128 2004/06/15 11:40:09 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.129 2004/06/16 07:45:24 danielk1977 Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -459,6 +459,7 @@ static void pager_reset(Pager *pPager){ */ static int pager_unwritelock(Pager *pPager){ PgHdr *pPg; + assert( !pPager->memDb ); if( pPager->statepAll; pPg; pPg=pNext){ +#ifndef NDEBUG + if( pPager->memDb ){ + PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); + assert( !pPg->alwaysRollback ); + assert( !pHist->pOrig ); + assert( !pHist->pStmt ); + } +#endif pNext = pPg->pNextAll; sqliteFree(pPg); } @@ -1939,6 +1948,7 @@ int sqlite3pager_unref(void *pData){ */ static int pager_open_journal(Pager *pPager){ int rc; + assert( !pPager->memDb ); assert( pPager->state>=PAGER_RESERVED ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); @@ -2278,6 +2288,8 @@ int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){ PgHdr *pPg; + if( pPager->memDb ) return; + pPg = pager_lookup(pPager, pgno); pPg->alwaysRollback = 1; if( pPg && pPg->dirty ){ @@ -2374,6 +2386,14 @@ int sqlite3pager_commit(Pager *pPager){ pPg->pPrevStmt = pPg->pNextStmt = 0; pPg = pPg->pDirty; } +#ifndef NDEBUG + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); + assert( !pPg->alwaysRollback ); + assert( !pHist->pOrig ); + assert( !pHist->pStmt ); + } +#endif pPager->pStmt = 0; pPager->state = PAGER_SHARED; return SQLITE_OK; @@ -2437,7 +2457,13 @@ int sqlite3pager_rollback(Pager *pPager){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; - if( !p->alwaysRollback && !p->dirty ) continue; + assert( !p->alwaysRollback ); + if( !p->dirty ){ + assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pOrig ); + assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt ); + continue; + } + pHist = PGHDR_TO_HIST(p, pPager); if( pHist->pOrig ){ memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize); diff --git a/src/util.c b/src/util.c index 80a69912fe..002bc2d355 100644 --- a/src/util.c +++ b/src/util.c @@ -14,12 +14,29 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.101 2004/06/12 00:42:35 danielk1977 Exp $ +** $Id: util.c,v 1.102 2004/06/16 07:45:29 danielk1977 Exp $ */ #include "sqliteInt.h" #include #include +#if SQLITE_DEBUG>2 && defined(__GLIBC__) +#include +void print_stack_trace(){ + void *bt[30]; + int i; + int n = backtrace(bt, 30); + + fprintf(stderr, "STACK: "); + for(i=0; i1 + print_stack_trace(); fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n", ++memcnt, n, (int)p, zFile,line); #endif @@ -189,6 +207,7 @@ void *sqlite3Realloc_(void *oldP, int n, char *zFile, int line){ memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int)); free(oldPi); #if SQLITE_DEBUG>1 + print_stack_trace(); fprintf(stderr,"%06d realloc %d to %d bytes at 0x%x to 0x%x at %s:%d\n", ++memcnt, oldN, n, (int)oldP, (int)p, zFile, line); #endif diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 6c0a131ba1..b9d23b36ce 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -746,9 +746,10 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){ ctx.isError = 0; (*pAgg->apFunc[i]->xFinalize)(&ctx); pMem->z = ctx.pAgg; - if( pMem->z!=0 && pMem->z!=pMem->z ){ + if( pMem->z!=0 && pMem->z!=pMem->zShort ){ sqliteFree(pMem->z); } + sqlite3VdbeMemRelease(&ctx.s); }else{ sqlite3VdbeMemRelease(pMem); } diff --git a/tool/memleak3.tcl b/tool/memleak3.tcl new file mode 100644 index 0000000000..69bc4ae88e --- /dev/null +++ b/tool/memleak3.tcl @@ -0,0 +1,106 @@ +#/bin/sh +# \ +exec `which tclsh` $0 "$@" +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +###################################################################### + +set doco " +This script is a tool to help track down memory leaks in the sqlite +library. The library must be compiled with the preprocessor symbol +SQLITE_DEBUG set to at least 2. It must be set to 3 to enable stack traces. + +To use, run the leaky application and save the standard error output. +Then, execute this program with the first argument the name of the +application binary (or interpreter) and the second argument the name of the +text file that contains the collected stderr output. + +If all goes well a summary of unfreed allocations is printed out. If the +GNU C library is in use and SQLITE_DEBUG is 3 or greater a stack trace is +printed out for each unmatched allocation. + +Example: + +$ ./testfixture ../sqlite/test/select1.test 2> memtrace.out +$ tclsh $argv0 ./testfixture memtrace.out +" + +# If stack traces are enabled, the 'addr2line' program is called to +# translate a binary stack address into a human-readable form. +set addr2line addr2line + +if { [llength $argv]!=2 } { + puts "Usage: $argv0 " + puts "" + puts [string trim $doco] + exit -1 +} + + +proc process_input {input_file array_name} { + upvar $array_name mem + set input [open $input_file] + + set MALLOC {([[:digit:]]+) malloc ([[:digit:]]+) bytes at 0x([[:xdigit:]]+)} + set STACK {^STACK: (.*)$} + set FREE {[[:digit:]]+ free ([[:digit:]]+) bytes at 0x([[:xdigit:]]+)} + set REALLOC {([[:digit:]]+) realloc ([[:digit:]]+) to ([[:digit:]]+)} + append REALLOC { bytes at 0x([[:xdigit:]]+) to 0x([[:xdigit:]]+)} + + set stack "" + while { ![eof $input] } { + set line [gets $input] + if {[regexp $STACK $line dummy stack]} { + # Do nothing. The variable $stack now stores the hexadecimal stack dump + # for the next malloc() or realloc(). + + } elseif { [regexp $MALLOC $line dummy mallocid bytes addr] } { + # If this is a 'malloc' line, set an entry in the mem array. Each entry + # is a list of length three, the number of bytes allocated , the malloc + # number and the stack dump when it was allocated. + set mem($addr) [list $bytes "malloc $mallocid" $stack] + set stack "" + + } elseif { [regexp $FREE $line dummy bytes addr] } { + # If this is a 'free' line, remove the entry from the mem array. If the + # entry does not exist, or is the wrong number of bytes, announce a + # problem. This is more likely a bug in the regular expressions for + # this script than an SQLite defect. + if { [lindex $mem($addr) 0] != $bytes } { + error "byte count mismatch" + } + unset mem($addr) + + } elseif { [regexp $REALLOC $line dummy mallocid ob b oa a] } { + # If it is a realloc line, remove the old mem entry and add a new one. + unset mem($oa); + set mem($a) [list $b "realloc $mallocid" $stack] + set stack "" + } else { + # puts "REJECT: $line" + } + } + + close $input +} + +process_input [lindex $argv 1] mem +set exe [lindex $argv 0] + +foreach key [array names mem] { + set bytes [lindex $mem($key) 0] + set mallocid [lindex $mem($key) 1] + set stack [lindex $mem($key) 2] + puts "Leaked $bytes bytes at 0x$key: $mallocid" + foreach frame [lrange $stack 1 10] { + foreach {f l} [split [exec $addr2line -f --exe=$exe $frame] \n] {} + puts [format "%-30s %s" $f $l] + } + if {[llength $stack]>0 } {puts ""} +} +