Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix two more memory leaks. (CVS 1603) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
98b48704a1ce983677cdb269c24f7bca |
User & Date: | danielk1977 2004-06-16 07:45:24.000 |
Context
2004-06-16
| ||
10:39 | Fix handling of a failed malloc() in various places (CVS 1604) (check-in: 7d8edce4c1 user: danielk1977 tags: trunk) | |
07:45 | Fix two more memory leaks. (CVS 1603) (check-in: 98b48704a1 user: danielk1977 tags: trunk) | |
03:02 | Documentation updates and changes the publish.sh script. (CVS 1602) (check-in: e9a77f8972 user: drh tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $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" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
455 456 457 458 459 460 461 462 463 464 465 466 467 468 | ** ** TODO: Consider keeping the journal file open for temporary databases. ** This might give a performance improvement on windows where opening ** a file is an expensive operation. */ static int pager_unwritelock(Pager *pPager){ PgHdr *pPg; if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3pager_stmt_commit(pPager); if( pPager->stmtOpen ){ sqlite3OsClose(&pPager->stfd); pPager->stmtOpen = 0; | > | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | ** ** TODO: Consider keeping the journal file open for temporary databases. ** This might give a performance improvement on windows where opening ** a file is an expensive operation. */ static int pager_unwritelock(Pager *pPager){ PgHdr *pPg; assert( !pPager->memDb ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3pager_stmt_commit(pPager); if( pPager->stmtOpen ){ sqlite3OsClose(&pPager->stfd); pPager->stmtOpen = 0; |
︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 | } default: { /* Do nothing */ break; } } for(pPg=pPager->pAll; pPg; pPg=pNext){ pNext = pPg->pNextAll; sqliteFree(pPg); } if( !pPager->memDb ){ sqlite3OsClose(&pPager->fd); } assert( pPager->journalOpen==0 ); | > > > > > > > > | 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 | } default: { /* Do nothing */ break; } } 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); } if( !pPager->memDb ){ sqlite3OsClose(&pPager->fd); } assert( pPager->journalOpen==0 ); |
︙ | ︙ | |||
1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 | ** or EXCLUSIVE lock on the database file when this routine is called. ** ** Return SQLITE_OK if everything. Return an error code and release the ** write lock if anything goes wrong. */ static int pager_open_journal(Pager *pPager){ int rc; assert( pPager->state>=PAGER_RESERVED ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); sqlite3pager_pagecount(pPager); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); | > | 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 | ** or EXCLUSIVE lock on the database file when this routine is called. ** ** Return SQLITE_OK if everything. Return an error code and release the ** write lock if anything goes wrong. */ static int pager_open_journal(Pager *pPager){ int rc; assert( !pPager->memDb ); assert( pPager->state>=PAGER_RESERVED ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); sqlite3pager_pagecount(pPager); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); |
︙ | ︙ | |||
2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 | ** is first added to the freelist, this routine is called. When reused, ** the dont_rollback() routine is called. But because the page contains ** critical data, we still need to be sure it gets rolled back in spite ** of the dont_rollback() call. */ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){ PgHdr *pPg; pPg = pager_lookup(pPager, pgno); pPg->alwaysRollback = 1; if( pPg && pPg->dirty ){ if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){ /* If this pages is the last page in the file and the file has grown ** during the current transaction, then do NOT mark the page as clean. | > > | 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 | ** is first added to the freelist, this routine is called. When reused, ** the dont_rollback() routine is called. But because the page contains ** critical data, we still need to be sure it gets rolled back in spite ** of the dont_rollback() call. */ 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 ){ if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){ /* If this pages is the last page in the file and the file has grown ** during the current transaction, then do NOT mark the page as clean. |
︙ | ︙ | |||
2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 | clearHistory(PGHDR_TO_HIST(pPg, pPager)); pPg->dirty = 0; pPg->inJournal = 0; pPg->inStmt = 0; pPg->pPrevStmt = pPg->pNextStmt = 0; pPg = pPg->pDirty; } pPager->pStmt = 0; pPager->state = PAGER_SHARED; return SQLITE_OK; } if( pPager->dirtyCache==0 ){ /* Exit early (without doing the time-consuming sqlite3OsSync() calls) ** if there have been no changes to the database file. */ | > > > > > > > > | 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 | clearHistory(PGHDR_TO_HIST(pPg, pPager)); pPg->dirty = 0; pPg->inJournal = 0; pPg->inStmt = 0; 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; } if( pPager->dirtyCache==0 ){ /* Exit early (without doing the time-consuming sqlite3OsSync() calls) ** if there have been no changes to the database file. */ |
︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 | int sqlite3pager_rollback(Pager *pPager){ int rc; TRACE2("ROLLBACK %d\n", pPager->fd.h); if( pPager->memDb ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; | | > > > > > > | 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 | int sqlite3pager_rollback(Pager *pPager){ int rc; TRACE2("ROLLBACK %d\n", pPager->fd.h); if( pPager->memDb ){ PgHdr *p; for(p=pPager->pAll; p; p=p->pNextAll){ PgHistory *pHist; 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); TRACE2("ROLLBACK-PAGE %d\n", p->pgno); }else{ TRACE2("PAGE %d is clean\n", p->pgno); } |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** | | > > > > > > > > > > > > > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** ** $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. */ int sqlite3_malloc_failed = 0; |
︙ | ︙ | |||
78 79 80 81 82 83 84 85 86 87 88 89 90 91 | sqlite3_nMalloc++; for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122; pi[N_GUARD] = n; for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344; p = &pi[N_GUARD+1]; memset(p, bZero==0, n); #if SQLITE_DEBUG>1 fprintf(stderr,"%06d malloc %d bytes at 0x%x from %s:%d\n", ++memcnt, n, (int)p, zFile,line); #endif return p; } /* | > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | sqlite3_nMalloc++; for(i=0; i<N_GUARD; i++) pi[i] = 0xdead1122; pi[N_GUARD] = n; for(i=0; i<N_GUARD; i++) pi[k+1+N_GUARD+i] = 0xdead3344; 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 return p; } /* |
︙ | ︙ | |||
185 186 187 188 189 190 191 192 193 194 195 196 197 198 | memcpy(p, oldP, n>oldN ? oldN : n); if( n>oldN ){ memset(&((char*)p)[oldN], 0, n-oldN); } memset(oldPi, 0xab, (oldK+N_GUARD+2)*sizeof(int)); free(oldPi); #if SQLITE_DEBUG>1 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 return p; } /* | > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | memcpy(p, oldP, n>oldN ? oldN : n); if( n>oldN ){ memset(&((char*)p)[oldN], 0, n-oldN); } 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 return p; } /* |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
742 743 744 745 746 747 748 | ctx.s.flags = MEM_Null; ctx.pAgg = pMem->z; ctx.cnt = pMem->i; ctx.isStep = 0; ctx.isError = 0; (*pAgg->apFunc[i]->xFinalize)(&ctx); pMem->z = ctx.pAgg; | | > | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 | ctx.s.flags = MEM_Null; ctx.pAgg = pMem->z; ctx.cnt = pMem->i; ctx.isStep = 0; ctx.isError = 0; (*pAgg->apFunc[i]->xFinalize)(&ctx); pMem->z = ctx.pAgg; if( pMem->z!=0 && pMem->z!=pMem->zShort ){ sqliteFree(pMem->z); } sqlite3VdbeMemRelease(&ctx.s); }else{ sqlite3VdbeMemRelease(pMem); } } sqliteFree(pElem); rc=sqlite3BtreeNext(pCsr, &res); } |
︙ | ︙ |
Added tool/memleak3.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 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 ""} } |