SQLite

Check-in [519bc9d997]
Login

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

Overview
Comment:Rig the sqliteMalloc() routine so that we can make it fail multiple times in a row. Modify the malloc.test procedure to make malloc fail in this way and verify that the failures are still handled correctly. (CVS 2121)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 519bc9d9975bbdb4ba056799534d5c465e0cd042
User & Date: drh 2004-11-20 19:18:01.000
Context
2004-11-20
19:18
Omit the maximum loop count on the random name chooser in the VACUUM command. Add a comment to explain why this is safe and does not result in an infinite loop. Ticket #1009. (CVS 2122) (check-in: 1241086f23 user: drh tags: trunk)
19:18
Rig the sqliteMalloc() routine so that we can make it fail multiple times in a row. Modify the malloc.test procedure to make malloc fail in this way and verify that the failures are still handled correctly. (CVS 2121) (check-in: 519bc9d997 user: drh tags: trunk)
18:13
Fix segfaults that might occur after a malloc failure. (CVS 2119) (check-in: 368774487e user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.340 2004/11/16 15:50:20 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it.  If the OS lacks













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.341 2004/11/20 19:18:01 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it.  If the OS lacks
246
247
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262
extern int sqlite3_malloc_failed;

/*
** The following global variables are used for testing and debugging
** only.  They only work if SQLITE_DEBUG is defined.
*/
#ifdef SQLITE_DEBUG
extern int sqlite3_nMalloc;       /* Number of sqliteMalloc() calls */
extern int sqlite3_nFree;         /* Number of sqliteFree() calls */
extern int sqlite3_iMallocFail;   /* Fail sqliteMalloc() after this many calls */

#endif

/*
** Name of the master database table.  The master database table
** is a special table that holds the names and attributes of all
** user tables and indices.
*/







|
|
|
>







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
extern int sqlite3_malloc_failed;

/*
** The following global variables are used for testing and debugging
** only.  They only work if SQLITE_DEBUG is defined.
*/
#ifdef SQLITE_DEBUG
extern int sqlite3_nMalloc;      /* Number of sqliteMalloc() calls */
extern int sqlite3_nFree;        /* Number of sqliteFree() calls */
extern int sqlite3_iMallocFail;  /* Fail sqliteMalloc() after this many calls */
extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
#endif

/*
** Name of the master database table.  The master database table
** is a special table that holds the names and attributes of all
** user tables and indices.
*/
Changes to src/test1.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.115 2004/11/19 07:07:31 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.116 2004/11/20 19:18:01 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

742
743
744
745
746
747
748
749
750
751





752
753
754
755
756
757
758
759
760
761

762
763
764
765
766





767

768
769
770
771
772
773
774
  z = sqlite3_mprintf(argv[1], argv[2]);
  Tcl_AppendResult(interp, z, 0);
  sqlite3_free(z);
  return TCL_OK;
}

/*
** Usage: sqlite_malloc_fail N
**
** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism





** and reset the sqlite3_malloc_failed variable is N==0.
*/
#ifdef SQLITE_DEBUG
static int sqlite_malloc_fail(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
  int n;

  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;





  sqlite3_iMallocFail = n;

  sqlite3_malloc_failed = 0;
  return TCL_OK;
}
#endif

/*
** Usage: sqlite_malloc_stat







|

|
>
>
>
>
>
|









>
|




>
>
>
>
>

>







742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  z = sqlite3_mprintf(argv[1], argv[2]);
  Tcl_AppendResult(interp, z, 0);
  sqlite3_free(z);
  return TCL_OK;
}

/*
** Usage: sqlite_malloc_fail N  ?REPEAT-INTERVAL?
**
** Rig sqliteMalloc() to fail on the N-th call and every REPEAT-INTERVAL call
** after that.  If REPEAT-INTERVAL is 0 or is omitted, then only a single
** malloc will fail.  If REPEAT-INTERVAL is 1 then all mallocs after the
** first failure will continue to fail on every call.  If REPEAT-INTERVAL is
** 2 then every other malloc will fail.  And so forth.
**
** Turn off this mechanism and reset the sqlite3_malloc_failed variable is N==0.
*/
#ifdef SQLITE_DEBUG
static int sqlite_malloc_fail(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
  int n;
  int rep;
  if( argc!=2 && argc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
    return TCL_ERROR;
  }
  if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
  if( argc==3 ){
    if( Tcl_GetInt(interp, argv[2], &rep) ) return TCL_ERROR;
  }else{
    rep = 0;
  }
  sqlite3_iMallocFail = n;
  sqlite3_iMallocReset = rep;
  sqlite3_malloc_failed = 0;
  return TCL_OK;
}
#endif

/*
** Usage: sqlite_malloc_stat
Changes to src/util.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.121 2004/11/04 04:34:15 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

#if SQLITE_DEBUG>2 && defined(__GLIBC__)
#include <execinfo.h>







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.122 2004/11/20 19:18:01 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

#if SQLITE_DEBUG>2 && defined(__GLIBC__)
#include <execinfo.h>
47
48
49
50
51
52
53
54



55
56
57
58

59
60
61
62
63
64
65
** If SQLITE_DEBUG is defined, then use versions of malloc() and
** free() that track memory usage and check for buffer overruns.
*/
#ifdef SQLITE_DEBUG

/*
** For keeping track of the number of mallocs and frees.   This
** is used to check for memory leaks.



*/
int sqlite3_nMalloc;         /* Number of sqliteMalloc() calls */
int sqlite3_nFree;           /* Number of sqliteFree() calls */
int sqlite3_iMallocFail;     /* Fail sqliteMalloc() after this many calls */

#if SQLITE_DEBUG>1
static int memcnt = 0;
#endif

/*
** Number of 32-bit guard words
*/







|
>
>
>




>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
** If SQLITE_DEBUG is defined, then use versions of malloc() and
** free() that track memory usage and check for buffer overruns.
*/
#ifdef SQLITE_DEBUG

/*
** For keeping track of the number of mallocs and frees.   This
** is used to check for memory leaks.  The iMallocFail and iMallocReset
** values are used to simulate malloc() failures during testing in 
** order to verify that the library correctly handles an out-of-memory
** condition.
*/
int sqlite3_nMalloc;         /* Number of sqliteMalloc() calls */
int sqlite3_nFree;           /* Number of sqliteFree() calls */
int sqlite3_iMallocFail;     /* Fail sqliteMalloc() after this many calls */
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
#if SQLITE_DEBUG>1
static int memcnt = 0;
#endif

/*
** Number of 32-bit guard words
*/
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    sqlite3_iMallocFail--;
    if( sqlite3_iMallocFail==0 ){
      sqlite3_malloc_failed++;
#if SQLITE_DEBUG>1
      fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
              n, zFile,line);
#endif
      sqlite3_iMallocFail--;
      return 0;
    }
  }
  if( n==0 ) return 0;
  k = (n+sizeof(int)-1)/sizeof(int);
  pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
  if( pi==0 ){







|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    sqlite3_iMallocFail--;
    if( sqlite3_iMallocFail==0 ){
      sqlite3_malloc_failed++;
#if SQLITE_DEBUG>1
      fprintf(stderr,"**** failed to allocate %d bytes at %s:%d\n",
              n, zFile,line);
#endif
      sqlite3_iMallocFail = sqlite3_iMallocReset;
      return 0;
    }
  }
  if( n==0 ) return 0;
  k = (n+sizeof(int)-1)/sizeof(int);
  pi = malloc( (N_GUARD*2+1+k)*sizeof(int));
  if( pi==0 ){
Changes to test/malloc.test.
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
#***********************************************************************
# This file attempts to check the library in an out-of-memory situation.
# When compiled with -DMEMORY_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: malloc.test,v 1.10 2004/06/30 09:49:24 danielk1977 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 -DMEMORY_DEBUG..."
   finish_test
   return
}

for {set go 1; set i 1} {$go} {incr i} {
  do_test malloc-1.$i {
     sqlite_malloc_fail 0
     catch {db close}
     catch {file delete -force test.db}
     catch {file delete -force test.db-journal}
     sqlite_malloc_fail $i
     set v [catch {sqlite3 db test.db} msg]
     if {$v} {
       set msg ""
     } else {
       set v [catch {execsql {
          CREATE TABLE t1(
             a int, b float, c double, d text, e varchar(20),







|


















|







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
#***********************************************************************
# This file attempts to check the library in an out-of-memory situation.
# When compiled with -DMEMORY_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: malloc.test,v 1.11 2004/11/20 19:18:01 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 -DMEMORY_DEBUG..."
   finish_test
   return
}

for {set go 1; set i 1} {$go} {incr i} {
  do_test malloc-1.$i {
     sqlite_malloc_fail 0
     catch {db close}
     catch {file delete -force test.db}
     catch {file delete -force test.db-journal}
     sqlite_malloc_fail $i [expr {$i%4}]
     set v [catch {sqlite3 db test.db} msg]
     if {$v} {
       set msg ""
     } else {
       set v [catch {execsql {
          CREATE TABLE t1(
             a int, b float, c double, d text, e varchar(20),