/ Check-in [62442529]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix some memory leak problems with corrupt.test and auto-vacuum databases. (CVS 2226)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6244252915fa312a6c4d192464023d95aaef4661
User & Date: danielk1977 2005-01-17 07:53:44
Context
2005-01-17
08:57
Fix a bug reported on the mailing list concerning a conflict between "INSERT INTO ... SELECT" statements and the "SELECT max(x) FROM tbl" optimization. (CVS 2227) check-in: 5a9da62a user: danielk1977 tags: trunk
07:53
Fix some memory leak problems with corrupt.test and auto-vacuum databases. (CVS 2226) check-in: 62442529 user: danielk1977 tags: trunk
03:42
Add incomplete, preliminary drafts of new documentation. (CVS 2225) check-in: a01159e8 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
491
492
493
494
495
496
497
498
499
500
501
502

503
504
505
506
507
508
509
510
511
512
513
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.240 2005/01/17 02:12:19 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
    return rc;
  }
  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);

  if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
    TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
    rc = sqlite3pager_write(pPtrmap);
    if( rc!=0 ){
      return rc;
    }
    pPtrmap[offset] = eType;
    put4byte(&pPtrmap[offset+1], parent);

  }

  sqlite3pager_unref(pPtrmap);
  return SQLITE_OK;
}

/*
** Read an entry from the pointer map.
**
** This routine retrieves the pointer map entry for page 'key', writing
** the type and parent page number to *pEType and *pPgno respectively.







|







 







|
<
<
|
|
>



|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
491
492
493
494
495
496
497
498


499
500
501
502
503
504
505
506
507
508
509
510
511
512
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.241 2005/01/17 07:53:44 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
    return rc;
  }
  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);

  if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
    TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
    rc = sqlite3pager_write(pPtrmap);
    if( rc==SQLITE_OK ){


      pPtrmap[offset] = eType;
      put4byte(&pPtrmap[offset+1], parent);
    }
  }

  sqlite3pager_unref(pPtrmap);
  return rc;
}

/*
** Read an entry from the pointer map.
**
** This routine retrieves the pointer map entry for page 'key', writing
** the type and parent page number to *pEType and *pPgno respectively.

Changes to src/build.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
687
688
689
690
691
692
693
694


695
696
697
698
699
700
701
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.290 2004/12/14 03:34:34 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
  }
#endif

  /* Make sure the new table name does not collide with an existing
  ** index or table name in the same database.  Issue an error message if
  ** it does.
  */
  if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) return;


  pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
  if( pTable ){
    sqlite3ErrorMsg(pParse, "table %T already exists", pName);
    goto begin_table_error;
  }
  if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 && 
      ( iDb==0 || !db->init.busy) ){







|







 







|
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.291 2005/01/17 07:53:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
  }
#endif

  /* Make sure the new table name does not collide with an existing
  ** index or table name in the same database.  Issue an error message if
  ** it does.
  */
  if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
    goto begin_table_error;
  }
  pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName);
  if( pTable ){
    sqlite3ErrorMsg(pParse, "table %T already exists", pName);
    goto begin_table_error;
  }
  if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 && 
      ( iDb==0 || !db->init.busy) ){

Changes to src/util.c.

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
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.126 2005/01/13 02:14:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

#if SQLITE_MEMDEBUG>2 && defined(__GLIBC__)
#include <execinfo.h>
void print_stack_trace(){
  void *bt[30];
  int i;
  int n = backtrace(bt, 30);

  sqlite3DebugPrintf("STACK: ");
  for(i=0; i<n;i++){
    sqlite3DebugPrintf("%p ", bt[i]);
  }
  sqlite3DebugPrintf("\n");
}
#else
#define print_stack_trace()
#endif

/*
** If malloc() ever fails, this global variable gets set to 1.







|












|

|

|







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
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.127 2005/01/17 07:53:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

#if SQLITE_MEMDEBUG>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.

Changes to test/all.test.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#    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.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: all.test,v 1.29 2005/01/17 01:33:14 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}

if {[file exists ./sqlite_test_count]} {
................................................................................
  memleak.test
}

# Test files btree2.test and btree4.test don't work if the 
# SQLITE_DEFAULT_AUTOVACUUM macro is defined to true (because they depend
# on tables being allocated starting at page 2).
#
# Also corrupt.test doesn't work, because currently SQLite can't detect
# corruption in pointer-map pages.
#
ifcapable default_autovacuum {
  lappend EXCLUDE btree2.test
  lappend EXCLUDE btree4.test
}

for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} {
  if {$Counter%2} {
................................................................................
      incr nErr
      lappend ::failList $tail
    }
  }
  if {[info exists Leak]} {
    lappend LeakList $Leak
  }

  # Reset the sqlite3_temp_directory variable for the next run of tests:
  sqlite3 db :memory:
  db eval {PRAGMA temp_store_directory = ""}
  db close
}

# Do one last test to look for a memory leak in the library.  This will
# only work if SQLite is compiled with the -DSQLITE_DEBUG=1 flag.
#
if {$LeakList!=""} {
  puts -nonewline memory-leak-test...







|







 







<
<
<







 







<
<
<
<
<







6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
57
58
59
60
61
62
63



64
65
66
67
68
69
70
..
82
83
84
85
86
87
88





89
90
91
92
93
94
95
#    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.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: all.test,v 1.30 2005/01/17 07:53:44 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {memleak_check}

if {[file exists ./sqlite_test_count]} {
................................................................................
  memleak.test
}

# Test files btree2.test and btree4.test don't work if the 
# SQLITE_DEFAULT_AUTOVACUUM macro is defined to true (because they depend
# on tables being allocated starting at page 2).
#



ifcapable default_autovacuum {
  lappend EXCLUDE btree2.test
  lappend EXCLUDE btree4.test
}

for {set Counter 0} {$Counter<$COUNT && $nErr==0} {incr Counter} {
  if {$Counter%2} {
................................................................................
      incr nErr
      lappend ::failList $tail
    }
  }
  if {[info exists Leak]} {
    lappend LeakList $Leak
  }





}

# Do one last test to look for a memory leak in the library.  This will
# only work if SQLite is compiled with the -DSQLITE_DEBUG=1 flag.
#
if {$LeakList!=""} {
  puts -nonewline memory-leak-test...

Changes to test/corrupt.test.

9
10
11
12
13
14
15
16



17
18
19
20
21
22
23
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt.test,v 1.2 2005/01/16 23:21:00 drh Exp $




set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Construct a large database for testing.
#
do_test corrupt-1.1 {







|
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt.test,v 1.3 2005/01/17 07:53:44 danielk1977 Exp $

catch {file delete -force test.db}
catch {file delete -force test.db-journal}

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Construct a large database for testing.
#
do_test corrupt-1.1 {

Changes to test/memleak.test.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
37
38
39
40
41
42
43
44
45









46
47
48
49
50
51
52
#    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.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: memleak.test,v 1.7 2004/09/03 18:38:46 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {
  catch {db close}
  memleak_check
................................................................................
  quick.test
  malloc.test
  misuse.test
  memleak.test
  btree2.test
  trans.test
  crash.test
  corrupt.test
}









if {[sqlite3 -has-codec]} {
  # lappend EXCLUDE 
}
if {[llength $argv]>0} {
  set FILELIST $argv
  set argv {}
} else {







|







 







|

>
>
>
>
>
>
>
>
>







6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
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
#    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.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: memleak.test,v 1.8 2005/01/17 07:53:44 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
rename finish_test really_finish_test
proc finish_test {} {
  catch {db close}
  memleak_check
................................................................................
  quick.test
  malloc.test
  misuse.test
  memleak.test
  btree2.test
  trans.test
  crash.test
  autovacuum_crash.test
}
# Test files btree2.test and btree4.test don't work if the 
# SQLITE_DEFAULT_AUTOVACUUM macro is defined to true (because they depend
# on tables being allocated starting at page 2).
#
ifcapable default_autovacuum {
  lappend EXCLUDE btree2.test
  lappend EXCLUDE btree4.test
}

if {[sqlite3 -has-codec]} {
  # lappend EXCLUDE 
}
if {[llength $argv]>0} {
  set FILELIST $argv
  set argv {}
} else {

Changes to test/pager.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
407
408
409
410
411
412
413

414
415
416



417
418
419
420
421
422
423
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is page cache subsystem.
#
# $Id: pager.test,v 1.19 2005/01/13 11:07:54 danielk1977 Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info commands pager_open]!=""} {
db close
................................................................................
  set ::p2 [pager_open :memory: 10]
  pager_truncate $::p2 5
} {}
do_test pager-4.6.3 {
  for {set i 1} {$i<5} {incr i} {
    set p [page_get $::p2 $i]
    page_write $p "Page $i"

    pager_commit $::p2
  }
  pager_truncate $::p2 3



} {}

do_test pager-4.99 {
  pager_close $::p1
} {}









|







 







>



>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is page cache subsystem.
#
# $Id: pager.test,v 1.20 2005/01/17 07:53:44 danielk1977 Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info commands pager_open]!=""} {
db close
................................................................................
  set ::p2 [pager_open :memory: 10]
  pager_truncate $::p2 5
} {}
do_test pager-4.6.3 {
  for {set i 1} {$i<5} {incr i} {
    set p [page_get $::p2 $i]
    page_write $p "Page $i"
    page_unref $p
    pager_commit $::p2
  }
  pager_truncate $::p2 3
} {}
do_test pager-4.6.4 {
  pager_close $::p2
} {}

do_test pager-4.99 {
  pager_close $::p1
} {}


Changes to test/pragma.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
704
705
706
707
708
709
710





711
712
713
714
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the PRAGMA command.
#
# $Id: pragma.test,v 1.31 2005/01/10 02:48:49 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Test organization:
#
# pragma-1.*: Test cache_size, default_cache_size and synchronous on main db.
................................................................................
do_test pragma-10.3 {
  execsql {
    DELETE FROM t1;
  }
} {1}

} ;# ifcapable trigger






finish_test









|







 







>
>
>
>
>




8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the PRAGMA command.
#
# $Id: pragma.test,v 1.32 2005/01/17 07:53:44 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Test organization:
#
# pragma-1.*: Test cache_size, default_cache_size and synchronous on main db.
................................................................................
do_test pragma-10.3 {
  execsql {
    DELETE FROM t1;
  }
} {1}

} ;# ifcapable trigger

# Reset the sqlite3_temp_directory variable for the next run of tests:
sqlite3 dbX :memory:
dbX eval {PRAGMA temp_store_directory = ""}
dbX close

finish_test


Changes to tool/memleak3.tcl.

9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
..
43
44
45
46
47
48
49

50
51
52
53
54
55
56
#    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
................................................................................


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] } {







|
>







 







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#    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_MEMDEBUG 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
................................................................................


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 {^[[:digit:]]+: STACK: (.*)$}
  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] } {