]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix two more memory leaks. (CVS 1603)
authordanielk1977 <danielk1977@noemail.net>
Wed, 16 Jun 2004 07:45:24 +0000 (07:45 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 16 Jun 2004 07:45:24 +0000 (07:45 +0000)
FossilOrigin-Name: 98b48704a1ce983677cdb269c24f7bca4ed606f7

manifest
manifest.uuid
src/pager.c
src/util.c
src/vdbeaux.c
tool/memleak3.tcl [new file with mode: 0644]

index 8ce04374f32965c32df1771324d0fcebec3e816e..287708ef0e2ea8c678dbeceac0097e877e92b139 100644 (file)
--- 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
index 38bdd5ba6519e38929de212c41a5f9224b1b7d25..e57d2d68228b63d45e1ec91270cbcd4a086e73c1 100644 (file)
@@ -1 +1 @@
-e9a77f8972128550f6ff98dcf854eb7680eaee8b
\ No newline at end of file
+98b48704a1ce983677cdb269c24f7bca4ed606f7
\ No newline at end of file
index 383c481f77fc1958f7e56c2a248ed13fd5b43cc4..1a6319bd4061cbc78a8c663e84f36367c0f92c32 100644 (file)
@@ -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->state<PAGER_RESERVED ){
     return SQLITE_OK;
   }
@@ -1354,6 +1355,14 @@ int sqlite3pager_close(Pager *pPager){
     }
   }
   for(pPg=pPager->pAll; 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);
index 80a69912fefc55b54cec028876b5d4a7cdbececd..002bc2d3555b1187128f1dfda2ea327cc327e5c9 100644 (file)
 ** 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 <stdarg.h>
 #include <ctype.h>
 
+#if SQLITE_DEBUG>2 && defined(__GLIBC__)
+#include <execinfo.h>
+void print_stack_trace(){
+  void *bt[30];
+  int i;
+  int n = backtrace(bt, 30);
+
+  fprintf(stderr, "STACK: ");
+  for(i=0; i<n;i++){
+    fprintf(stderr, "%p ", bt[i]);
+  }
+  fprintf(stderr, "\n");
+}
+#else
+#define print_stack_trace()
+#endif
+
 /*
 ** If malloc() ever fails, this global variable gets set to 1.
 ** This causes the library to abort and never again function.
@@ -82,6 +99,7 @@ void *sqlite3Malloc_(int n, int bZero, char *zFile, int line){
   p = &pi[N_GUARD+1];
   memset(p, bZero==0, n);
 #if SQLITE_DEBUG>1
+  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
index 6c0a131ba1da4750070f53772b1282039e5d7818..b9d23b36ce4b5100f763612a12e052153ab63a4f 100644 (file)
@@ -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 (file)
index 0000000..69bc4ae
--- /dev/null
@@ -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 <binary file> <mem trace file>"
+  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 ""}
+}
+