SQLite

Check-in [70b2ed2afc]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 70b2ed2afcf1757d1c58f3a83dad4a5fb226ae63
User & Date: danielk1977 2008-06-26 08:29:34.000
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: cdd4cf4ce2 user: danielk1977 tags: trunk)
08:29
Fix a race condition in sqlite3_initialize(). (CVS 5310) (check-in: 70b2ed2afc user: danielk1977 tags: trunk)
02:53
Documentation updates. No changes to code. (CVS 5309) (check-in: cdc4e75a9f user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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
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
** 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;
}








>

>
>

>
>

>

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











>
>
>







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
** 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;
}

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
*/
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;







|







148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
*/
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
**    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







|







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.
**
******************************************************************************
**
** 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
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

/*
** 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;







<

<




<
<
|
<
<







239
240
241
242
243
244
245

246

247
248
249
250


251


252
253
254
255
256
257
258

/*
** 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.
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.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













|







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.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
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759


1760
1761
1762
1763
1764
1765
1766
  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 */
  void *pHeap;                      /* Heap storage space */
  int nHeap;                        /* Size of pHeap[] */
  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) {                        \







<
<
<
<
<
<
















|
>
>







1730
1731
1732
1733
1734
1735
1736






1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
  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 */
  void *pHeap;                      /* Heap storage space */
  int nHeap;                        /* Size of pHeap[] */
  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.
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
# 2008 June 17
#
# 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.
#
#***********************************************************************
#
# $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
  set var(total) 0
  foreach {name value} [read_mutex_counters] {
    set var($name) $value
    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











|

















|
>
|







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
# 2008 June 17
#
# 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.
#
#***********************************************************************
#
# $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
  set var(total) 0
  foreach {name value} [read_mutex_counters] {
    set var($name) $value
    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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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 {







|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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 {
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
    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);
      }
    } {}







|

>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
#    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
}








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
#    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
}
38
39
40
41
42
43
44

45
46
47
48
49
50
51
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







>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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