/ Check-in [70b2ed2a]
Login

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

Overview
Comment:Fix a race condition in sqlite3_initialize(). (CVS 5310)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 70b2ed2afcf1757d1c58f3a83dad4a5fb226ae63
User & Date: danielk1977 2008-06-26 08:29:34
Context
2008-06-26
10:41
Change the OS_XXX pre-processor symbols to SQLITE_OS_XXX. Symbols "OS_UNIX", "OS_WIN", "OS_WINCE", "OS_OS2" and "OS_OTHER" are now "SQLITE_OS_UNIX", "SQLITE_OS_WIN", "SQLITE_OS_WINCE", "SQLITE_OS_OS2" and "SQLITE_OS_OTHER", respectively. (CVS 5311) check-in: cdd4cf4c user: danielk1977 tags: trunk
08:29
Fix a race condition in sqlite3_initialize(). (CVS 5310) check-in: 70b2ed2a user: danielk1977 tags: trunk
02:53
Documentation updates. No changes to code. (CVS 5309) check-in: cdc4e75a user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
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
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.462 2008/06/25 17:19:01 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
................................................................................
** this routine will be called automatically by key routines such as
** sqlite3_open().  
**
** This routine is a no-op except on its very first call for the process,
** or for the first call after a call to sqlite3_shutdown.
*/
int sqlite3_initialize(void){

  int rc;


  if( sqlite3Config.isInit ) return SQLITE_OK;


  rc = sqlite3MutexInit();

  if( rc==SQLITE_OK ){
#ifndef SQLITE_MUTEX_NOOP




    sqlite3_mutex *pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
    sqlite3_mutex_enter(pMutex);
    if( sqlite3Config.isInit==0 ){
      sqlite3Config.isInit = 1;
      sqlite3StatusReset();
      if( rc==SQLITE_OK ) rc = sqlite3MallocInit();

      if( rc==SQLITE_OK ) rc = sqlite3_os_init();
      if( rc!=SQLITE_OK ){
        sqlite3Config.isInit = 0;
      }else{
        sqlite3Config.isInit = 2;



      }
    }

    sqlite3_mutex_leave(pMutex);





















  }
  return rc;
}

/*
** Undo the effects of sqlite3_initialize().  Must not be called while
** there are outstanding database connections or memory allocations or
** while any part of SQLite is otherwise in use in any thread.  This
** routine is not threadsafe.  Not by a long shot.
*/
int sqlite3_shutdown(void){



  sqlite3_os_end();
  sqlite3MallocEnd();
  sqlite3MutexEnd();
  sqlite3Config.isInit = 0;
  return SQLITE_OK;
}

................................................................................
*/
int sqlite3_config(int op, ...){
  va_list ap;
  int rc = SQLITE_OK;

  /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
  ** the SQLite library is in use. */
  if( sqlite3Config.isInit==2 ) return SQLITE_MISUSE;

  va_start(ap, op);
  switch( op ){
    case SQLITE_CONFIG_SINGLETHREAD: {
      /* Disable all mutexing */
      sqlite3Config.bCoreMutex = 0;
      sqlite3Config.bFullMutex = 0;







|







 







>

>
>

>
>

>

<
>
>
>
>
|
<
|
<
|
<
|
>
|
<
|
<
|
>
>
>
|
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











>
>
>







 







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.463 2008/06/26 08:29:34 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
................................................................................
** this routine will be called automatically by key routines such as
** sqlite3_open().  
**
** This routine is a no-op except on its very first call for the process,
** or for the first call after a call to sqlite3_shutdown.
*/
int sqlite3_initialize(void){
  static int inProgress = 0;
  int rc;

  /* If SQLite is already initialized, this call is a no-op. */
  if( sqlite3Config.isInit ) return SQLITE_OK;

  /* Make sure the mutex system is initialized. */
  rc = sqlite3MutexInit();

  if( rc==SQLITE_OK ){


    /* Initialize the malloc() system and the recursive pInitMutex mutex.
    ** This operation is protected by the STATIC_MASTER mutex.
    */
    sqlite3_mutex *pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);

    sqlite3_mutex_enter(pMaster);

    if( !sqlite3Config.isMallocInit ){

      rc = sqlite3MallocInit();
    }
    if( rc==SQLITE_OK ){

      sqlite3Config.isMallocInit = 1;

      if( !sqlite3Config.pInitMutex ){
        sqlite3Config.pInitMutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
        if( sqlite3Config.bCoreMutex && !sqlite3Config.pInitMutex ){
          rc = SQLITE_NOMEM;
        }
      }
    }
    sqlite3_mutex_leave(pMaster);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    /* Enter the recursive pInitMutex mutex. After doing so, if the
    ** sqlite3Config.isInit flag is true, then some other thread has
    ** finished doing the initialization. If the inProgress flag is
    ** true, then this function is being called recursively from within
    ** the sqlite3_os_init() call below. In either case, exit early.
    */
    sqlite3_mutex_enter(sqlite3Config.pInitMutex);
    if( sqlite3Config.isInit || inProgress ){
      sqlite3_mutex_leave(sqlite3Config.pInitMutex);
      return SQLITE_OK;
    }
    sqlite3StatusReset();
    inProgress = 1;
    rc = sqlite3_os_init();
    inProgress = 0;
    sqlite3Config.isInit = (rc==SQLITE_OK ? 1 : 0);
    sqlite3_mutex_leave(sqlite3Config.pInitMutex);
  }
  return rc;
}

/*
** Undo the effects of sqlite3_initialize().  Must not be called while
** there are outstanding database connections or memory allocations or
** while any part of SQLite is otherwise in use in any thread.  This
** routine is not threadsafe.  Not by a long shot.
*/
int sqlite3_shutdown(void){
  sqlite3_mutex_free(sqlite3Config.pInitMutex);
  sqlite3Config.pInitMutex = 0;
  sqlite3Config.isMallocInit = 0;
  sqlite3_os_end();
  sqlite3MallocEnd();
  sqlite3MutexEnd();
  sqlite3Config.isInit = 0;
  return SQLITE_OK;
}

................................................................................
*/
int sqlite3_config(int op, ...){
  va_list ap;
  int rc = SQLITE_OK;

  /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
  ** the SQLite library is in use. */
  if( sqlite3Config.isInit ) return SQLITE_MISUSE;

  va_start(ap, op);
  switch( op ){
    case SQLITE_CONFIG_SINGLETHREAD: {
      /* Disable all mutexing */
      sqlite3Config.bCoreMutex = 0;
      sqlite3Config.bFullMutex = 0;

Changes to src/os.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains OS interface code that is common to all
** architectures.
**
** $Id: os.c,v 1.116 2008/06/25 17:19:01 danielk1977 Exp $
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
#undef _SQLITE_OS_C_

/*
** The default SQLite sqlite3_vfs implementations do not allocate
................................................................................

/*
** Register a VFS with the system.  It is harmless to register the same
** VFS multiple times.  The new VFS becomes the default if makeDflt is
** true.
*/
int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
#ifndef SQLITE_MUTEX_NOOP
  sqlite3_mutex *mutex = 0;
#endif
#ifndef SQLITE_OMIT_AUTOINIT
  int rc = sqlite3_initialize();
  if( rc ) return rc;
#endif
#ifndef SQLITE_MUTEX_NOOP
  if( sqlite3Config.isInit!=1 ){
    mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
  }
#endif
  sqlite3_mutex_enter(mutex);
  vfsUnlink(pVfs);
  if( makeDflt || vfsList==0 ){
    pVfs->pNext = vfsList;
    vfsList = pVfs;
  }else{
    pVfs->pNext = vfsList->pNext;







|







 







<

<




<
<
|
<
<







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
239
240
241
242
243
244
245

246

247
248
249
250


251


252
253
254
255
256
257
258
**    May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains OS interface code that is common to all
** architectures.
**
** $Id: os.c,v 1.117 2008/06/26 08:29:34 danielk1977 Exp $
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
#undef _SQLITE_OS_C_

/*
** The default SQLite sqlite3_vfs implementations do not allocate
................................................................................

/*
** Register a VFS with the system.  It is harmless to register the same
** VFS multiple times.  The new VFS becomes the default if makeDflt is
** true.
*/
int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){

  sqlite3_mutex *mutex = 0;

#ifndef SQLITE_OMIT_AUTOINIT
  int rc = sqlite3_initialize();
  if( rc ) return rc;
#endif


  mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);


  sqlite3_mutex_enter(mutex);
  vfsUnlink(pVfs);
  if( makeDflt || vfsList==0 ){
    pVfs->pNext = vfsList;
    vfsList = pVfs;
  }else{
    pVfs->pNext = vfsList->pNext;

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
....
1752
1753
1754
1755
1756
1757
1758
1759


1760
1761
1762
1763
1764
1765
1766
**    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.729 2008/06/25 17:19:01 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
  int rc;             /* Result code stored here */
} InitData;

/*
** Structure containing global configuration data for the SQLite library.
**
** This structure also contains some state information.
**
** The Sqlite3Config.isInit variable indicates whether or not
** sqlite3_initialize() has already been called or not. Initially, isInit
** is 0. While sqlite3_initialize() is running, it is set to 1. After
** sqlite3_initialize has successfully run, the Sqlite3Config.isInit variable
** is set to 2. Calling sqlite3_shutdown() resets the value to 0.
*/
struct Sqlite3Config {
  int bMemstat;                     /* True to enable memory status */
  int bCoreMutex;                   /* True to enable core mutexing */
  int bFullMutex;                   /* True to enable full mutexing */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */
  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
................................................................................
  int mnReq, mxReq;                 /* Min and max heap requests sizes */
  void *pScratch;                   /* Scratch memory */
  int szScratch;                    /* Size of each scratch buffer */
  int nScratch;                     /* Number of scratch buffers */
  void *pPage;                      /* Page cache memory */
  int szPage;                       /* Size of each page in pPage[] */
  int nPage;                        /* Number of pages in pPage[] */
  int isInit;                       /* Initialization state */


};

/*
** Assuming zIn points to the first byte of a UTF-8 character,
** advance zIn to point to the first byte of the next UTF-8 character.
*/
#define SQLITE_SKIP_UTF8(zIn) {                        \







|







 







<
<
<
<
<
<







 







|
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1730
1731
1732
1733
1734
1735
1736






1737
1738
1739
1740
1741
1742
1743
....
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
**    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.730 2008/06/26 08:29:34 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
  int rc;             /* Result code stored here */
} InitData;

/*
** Structure containing global configuration data for the SQLite library.
**
** This structure also contains some state information.






*/
struct Sqlite3Config {
  int bMemstat;                     /* True to enable memory status */
  int bCoreMutex;                   /* True to enable core mutexing */
  int bFullMutex;                   /* True to enable full mutexing */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */
  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
................................................................................
  int mnReq, mxReq;                 /* Min and max heap requests sizes */
  void *pScratch;                   /* Scratch memory */
  int szScratch;                    /* Size of each scratch buffer */
  int nScratch;                     /* Number of scratch buffers */
  void *pPage;                      /* Page cache memory */
  int szPage;                       /* Size of each page in pPage[] */
  int nPage;                        /* Number of pages in pPage[] */
  int isInit;                       /* True after initialization has finished */
  int isMallocInit;                 /* True after malloc is initialized */
  sqlite3_mutex *pInitMutex;        /* Mutex used by sqlite3_initialize() */
};

/*
** Assuming zIn points to the first byte of a UTF-8 character,
** advance zIn to point to the first byte of the next UTF-8 character.
*/
#define SQLITE_SKIP_UTF8(zIn) {                        \

Changes to test/mutex1.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
..
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
#
#    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: mutex1.test,v 1.4 2008/06/19 17:54:33 drh Exp $

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

proc mutex_counters {varname} {
  upvar $varname var
................................................................................
    incr var(total) $value
  }
}

#-------------------------------------------------------------------------
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
# is called at the wrong time. And that the first time sqlite3_initialize 
# is called it obtains the 'static_master' mutex. Subsequent calls are

# no-ops that do not require a mutex.
#
do_test mutex1-1.0 {
  install_mutex_counters 1
} {SQLITE_MISUSE}

do_test mutex1-1.1 {
  db close
................................................................................
do_test mutex1-1.6 {
  sqlite3_initialize
} {SQLITE_OK}

do_test mutex1-1.7 {
  mutex_counters counters
  list $counters(total) $counters(static_master)
} {1 1}

do_test mutex1-1.8 {
  clear_mutex_counters
  sqlite3_initialize
} {SQLITE_OK}

do_test mutex1-1.9 {
................................................................................
    serialized   {fast recursive static_master static_mem static_prng}
  } {
    do_test mutex1.2.$mode.1 {
      catch {db close}
      sqlite3_shutdown
      sqlite3_config $mode
    } SQLITE_OK
  
    do_test mutex1.2.$mode.2 {

      clear_mutex_counters
      sqlite3 db test.db
      catchsql { CREATE TABLE abc(a, b, c) }
      db eval {
        INSERT INTO abc VALUES(1, 2, 3);
      }
    } {}







|







 







|
>
|







 







|







 







|

>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#
#    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: mutex1.test,v 1.5 2008/06/26 08:29:35 danielk1977 Exp $

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

proc mutex_counters {varname} {
  upvar $varname var
................................................................................
    incr var(total) $value
  }
}

#-------------------------------------------------------------------------
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
# is called at the wrong time. And that the first time sqlite3_initialize 
# is called it obtains the 'static_master' mutex 3 times and a recursive
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops 
# that do not require any mutexes.
#
do_test mutex1-1.0 {
  install_mutex_counters 1
} {SQLITE_MISUSE}

do_test mutex1-1.1 {
  db close
................................................................................
do_test mutex1-1.6 {
  sqlite3_initialize
} {SQLITE_OK}

do_test mutex1-1.7 {
  mutex_counters counters
  list $counters(total) $counters(static_master)
} {6 3}

do_test mutex1-1.8 {
  clear_mutex_counters
  sqlite3_initialize
} {SQLITE_OK}

do_test mutex1-1.9 {
................................................................................
    serialized   {fast recursive static_master static_mem static_prng}
  } {
    do_test mutex1.2.$mode.1 {
      catch {db close}
      sqlite3_shutdown
      sqlite3_config $mode
    } SQLITE_OK

    do_test mutex1.2.$mode.2 {
      sqlite3_initialize
      clear_mutex_counters
      sqlite3 db test.db
      catchsql { CREATE TABLE abc(a, b, c) }
      db eval {
        INSERT INTO abc VALUES(1, 2, 3);
      }
    } {}

Changes to test/quick.test.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
38
39
40
41
42
43
44

45
46
47
48
49
50
51
#    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: quick.test,v 1.83 2008/06/25 17:54:55 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
................................................................................
proc finish_test {} {}
set ISQUICK 1

set EXCLUDE {
  all.test
  async.test
  async2.test

  corrupt.test
  crash.test
  crash2.test
  crash3.test
  crash4.test
  crash5.test
  crash6.test







|







 







>







2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
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: quick.test,v 1.84 2008/06/26 08:29:35 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
................................................................................
proc finish_test {} {}
set ISQUICK 1

set EXCLUDE {
  all.test
  async.test
  async2.test
  async3.test
  corrupt.test
  crash.test
  crash2.test
  crash3.test
  crash4.test
  crash5.test
  crash6.test