/ Check-in [f6a8f577]
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:Enhance mutex initialization to prevent possible race conditions between sqlite3_initialize() and sqlite3_config(). Also, re-check sqlite3GlobalConfig.isInit after the mutex subsystem has been initialized.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mutexInitCmpSwap
Files: files | file ages | folders
SHA1: f6a8f577957769171acd72df3cc9aa5ad474d84b
User & Date: mistachkin 2015-09-11 05:06:15
Context
2015-09-11
23:24
Make sure that the mutex implementation can be altered after calling sqlite3_shutdown(). check-in: dc2cf897 user: mistachkin tags: mutexInitCmpSwap
05:06
Enhance mutex initialization to prevent possible race conditions between sqlite3_initialize() and sqlite3_config(). Also, re-check sqlite3GlobalConfig.isInit after the mutex subsystem has been initialized. check-in: f6a8f577 user: mistachkin tags: mutexInitCmpSwap
01:22
Updates to the sqlite3_value_subtype() and sqlite3_result_subtype() documentation and to test cases for json1 dealing with those interfaces. check-in: d6cadbe9 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/global.c.

170
171
172
173
174
175
176

177
178
179
180
181
182
183
   SQLITE_USE_URI,            /* bOpenUri */
   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
   0x7ffffffe,                /* mxStrlen */
   0,                         /* neverCorrupt */
   128,                       /* szLookaside */
   500,                       /* nLookaside */
   {0,0,0,0,0,0,0,0},         /* m */

   {0,0,0,0,0,0,0,0,0},       /* mutex */
   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
   (void*)0,                  /* pHeap */
   0,                         /* nHeap */
   0, 0,                      /* mnHeap, mxHeap */
   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */







>







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
   SQLITE_USE_URI,            /* bOpenUri */
   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
   0x7ffffffe,                /* mxStrlen */
   0,                         /* neverCorrupt */
   128,                       /* szLookaside */
   500,                       /* nLookaside */
   {0,0,0,0,0,0,0,0},         /* m */
   (void*)0,                  /* pMutex */
   {0,0,0,0,0,0,0,0,0},       /* mutex */
   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
   (void*)0,                  /* pHeap */
   0,                         /* nHeap */
   0, 0,                      /* mnHeap, mxHeap */
   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */

Changes to src/main.c.

167
168
169
170
171
172
173

174





175
176
177
178
179
180
181
...
380
381
382
383
384
385
386




387
388



389
390
391
392
393
394
395
  ** This operation is protected by the STATIC_MASTER mutex.  Note that
  ** MutexAlloc() is called for a static mutex prior to initializing the
  ** malloc subsystem - this implies that the allocation of a static
  ** mutex must not require support from the malloc subsystem.
  */
  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
  sqlite3_mutex_enter(pMaster);

  sqlite3GlobalConfig.isMutexInit = 1;





  if( !sqlite3GlobalConfig.isMallocInit ){
    rc = sqlite3MallocInit();
  }
  if( rc==SQLITE_OK ){
    sqlite3GlobalConfig.isMallocInit = 1;
    if( !sqlite3GlobalConfig.pInitMutex ){
      sqlite3GlobalConfig.pInitMutex =
................................................................................
      sqlite3GlobalConfig.bCoreMutex = 1;  /* Enable mutex on core */
      sqlite3GlobalConfig.bFullMutex = 1;  /* Enable mutex on connections */
      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */
    case SQLITE_CONFIG_MUTEX: {




      /* Specify an alternative mutex implementation */
      sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*);



      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */
    case SQLITE_CONFIG_GETMUTEX: {
      /* Retrieve the current mutex implementation */
      *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex;







>
|
>
>
>
>
>







 







>
>
>
>
|
|
>
>
>







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  ** This operation is protected by the STATIC_MASTER mutex.  Note that
  ** MutexAlloc() is called for a static mutex prior to initializing the
  ** malloc subsystem - this implies that the allocation of a static
  ** mutex must not require support from the malloc subsystem.
  */
  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
  sqlite3_mutex_enter(pMaster);
  if( sqlite3GlobalConfig.isInit ){
    assert( sqlite3GlobalConfig.isMutexInit );
    assert( sqlite3GlobalConfig.isMallocInit );
    sqlite3_mutex_leave(pMaster);
    return SQLITE_OK;
  }
  sqlite3GlobalConfig.isMutexInit = 1; /* possibly redundant */
  if( !sqlite3GlobalConfig.isMallocInit ){
    rc = sqlite3MallocInit();
  }
  if( rc==SQLITE_OK ){
    sqlite3GlobalConfig.isMallocInit = 1;
    if( !sqlite3GlobalConfig.pInitMutex ){
      sqlite3GlobalConfig.pInitMutex =
................................................................................
      sqlite3GlobalConfig.bCoreMutex = 1;  /* Enable mutex on core */
      sqlite3GlobalConfig.bFullMutex = 1;  /* Enable mutex on connections */
      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-63666-48755 */
    case SQLITE_CONFIG_MUTEX: {
      /* Atomically compare-and-swap the mutex implementation pointer to
       * help prevent a race condition with sqlite3MutexInit(). */
      if( sqlite3CompareAndSwap((void * volatile *)&sqlite3GlobalConfig.pMutex,
                                0, &sqlite3GlobalConfig.mutex)==0 ){
        /* Specify an alternative mutex implementation */
        sqlite3GlobalConfig.mutex = *va_arg(ap, sqlite3_mutex_methods*);
      }else{
        rc = SQLITE_ERROR;
      }
      break;
    }
#endif
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE>0 /* IMP: R-14450-37597 */
    case SQLITE_CONFIG_GETMUTEX: {
      /* Retrieve the current mutex implementation */
      *va_arg(ap, sqlite3_mutex_methods*) = sqlite3GlobalConfig.mutex;

Changes to src/mutex.c.

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
#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/*
** For debugging purposes, record when the mutex subsystem is initialized
** and uninitialized so that we can assert() if there is an attempt to
** allocate a mutex while the system is uninitialized.
*/
static SQLITE_WSD int mutexIsInit = 0;
#endif /* SQLITE_DEBUG */


#ifndef SQLITE_MUTEX_OMIT



















/*
** Initialize the mutex system.
*/
int sqlite3MutexInit(void){ 
  int rc = SQLITE_OK;

  if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
    /* If the xMutexAlloc method has not been set, then the user did not
    ** install a mutex implementation via sqlite3_config() prior to 
    ** sqlite3_initialize() being called. This block copies pointers to
    ** the default implementation into the sqlite3GlobalConfig structure.
    */
    sqlite3_mutex_methods const *pFrom;
    sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;

    if( sqlite3GlobalConfig.bCoreMutex ){
      pFrom = sqlite3DefaultMutex();
    }else{
      pFrom = sqlite3NoopMutex();
    }
    pTo->xMutexInit = pFrom->xMutexInit;
    pTo->xMutexEnd = pFrom->xMutexEnd;
    pTo->xMutexFree = pFrom->xMutexFree;
    pTo->xMutexEnter = pFrom->xMutexEnter;
    pTo->xMutexTry = pFrom->xMutexTry;
    pTo->xMutexLeave = pFrom->xMutexLeave;
    pTo->xMutexHeld = pFrom->xMutexHeld;
    pTo->xMutexNotheld = pFrom->xMutexNotheld;
    sqlite3MemoryBarrier();
    pTo->xMutexAlloc = pFrom->xMutexAlloc;
  }
  rc = sqlite3GlobalConfig.mutex.xMutexInit();

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif








|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|
>
|






<






|
<
<
<
<
<
<
<

<







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
#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/*
** For debugging purposes, record when the mutex subsystem is initialized
** and uninitialized so that we can assert() if there is an attempt to
** allocate a mutex while the system is uninitialized.
*/
static SQLITE_WSD int mutexIsInit = 0;
#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */


#ifndef SQLITE_MUTEX_OMIT
/*
** Copies a mutex implementation.  Both arguments must point to valid
** memory.
*/
static void mutexCopy(
  sqlite3_mutex_methods *pTo,
  sqlite3_mutex_methods const *pFrom
){
  pTo->xMutexInit = pFrom->xMutexInit;
  pTo->xMutexEnd = pFrom->xMutexEnd;
  pTo->xMutexFree = pFrom->xMutexFree;
  pTo->xMutexEnter = pFrom->xMutexEnter;
  pTo->xMutexTry = pFrom->xMutexTry;
  pTo->xMutexLeave = pFrom->xMutexLeave;
  pTo->xMutexHeld = pFrom->xMutexHeld;
  pTo->xMutexNotheld = pFrom->xMutexNotheld;
  pTo->xMutexAlloc = pFrom->xMutexAlloc;
}

/*
** Initialize the mutex system.
*/
int sqlite3MutexInit(void){ 
  int rc;
  if( sqlite3CompareAndSwap((void * volatile *)&sqlite3GlobalConfig.pMutex,
                            0, &sqlite3GlobalConfig.mutex)==0 ){
    /* If the xMutexAlloc method has not been set, then the user did not
    ** install a mutex implementation via sqlite3_config() prior to 
    ** sqlite3_initialize() being called. This block copies pointers to
    ** the default implementation into the sqlite3GlobalConfig structure.
    */
    sqlite3_mutex_methods const *pFrom;


    if( sqlite3GlobalConfig.bCoreMutex ){
      pFrom = sqlite3DefaultMutex();
    }else{
      pFrom = sqlite3NoopMutex();
    }
    mutexCopy(&sqlite3GlobalConfig.mutex, pFrom);







    sqlite3MemoryBarrier();

  }
  rc = sqlite3GlobalConfig.mutex.xMutexInit();

#ifdef SQLITE_DEBUG
  GLOBAL(int, mutexIsInit) = 1;
#endif

Changes to src/mutex_noop.c.

24
25
26
27
28
29
30






















31
32
33
34
35
36
37
** If compiled with SQLITE_DEBUG, then additional logic is inserted
** that does error checking on mutexes to make sure they are being
** called correctly.
*/
#include "sqliteInt.h"

#ifndef SQLITE_MUTEX_OMIT























#ifndef SQLITE_DEBUG
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
** If compiled with SQLITE_DEBUG, then additional logic is inserted
** that does error checking on mutexes to make sure they are being
** called correctly.
*/
#include "sqliteInt.h"

#ifndef SQLITE_MUTEX_OMIT

/*
** Try to provide an atomic compare-and-swap operation on a void pointer,
** needed for initialization only.
*/
void *sqlite3NoopCompareAndSwap(
  void *volatile *pCurVal,
  void *cmpVal,
  void *swapVal
){
  /*
  ** This platform may not have a way to perform an atomic compare-and-swap
  ** operation; therefore, use the fallback algorithm.
  **
  ** WARNING: This code is almost certainly not thread-safe.
  */
  void *oldVal = *pCurVal;
  if( oldVal==cmpVal ){
    *pCurVal = swapVal;
  }
  return oldVal;
}

#ifndef SQLITE_DEBUG
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/

Changes to src/mutex_unix.c.

82
83
84
85
86
87
88
89
90
91
92




























93
94
95
96
97
98
99

/*
** Try to provide a memory barrier operation, needed for initialization only.
*/
void sqlite3MemoryBarrier(void){
#if defined(SQLITE_MEMORY_BARRIER)
  SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
  __sync_synchronize();
#endif
}





























/*
** Initialize and deinitialize the mutex subsystem.
*/
static int pthreadMutexInit(void){ return SQLITE_OK; }
static int pthreadMutexEnd(void){ return SQLITE_OK; }








|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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

/*
** Try to provide a memory barrier operation, needed for initialization only.
*/
void sqlite3MemoryBarrier(void){
#if defined(SQLITE_MEMORY_BARRIER)
  SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__) && GCC_VERSION>=4001000
  __sync_synchronize();
#endif
}

/*
** Try to provide an atomic compare-and-swap operation on a void pointer,
** needed for initialization only.
*/
void *sqlite3CompareAndSwap(
  void *volatile *pCurVal,
  void *cmpVal,
  void *swapVal
){
#if defined(SQLITE_COMPARE_AND_SWAP)
  return SQLITE_COMPARE_AND_SWAP(pCurVal, cmpVal, swapVal);
#elif defined(__GNUC__) && GCC_VERSION>=4001000 && SQLITE_PTRSIZE>4
  return (void *)__sync_val_compare_and_swap_8(
      (u64 volatile *)pCurVal, (u64)cmpVal, (u64)swapVal);
#elif defined(__GNUC__) && GCC_VERSION>=4001000
  return (void *)__sync_val_compare_and_swap_4(
      (u32 volatile *)pCurVal, (u32)cmpVal, (u32)swapVal);
#else
  /*
  ** This platform may not have a way to perform an atomic compare-and-swap
  ** operation; therefore, use the fallback algorithm.
  **
  ** WARNING: This code is almost certainly not thread-safe.
  */
  return sqlite3NoopCompareAndSwap(pCurVal, cmpVal, swapVal);
#endif
}

/*
** Initialize and deinitialize the mutex subsystem.
*/
static int pthreadMutexInit(void){ return SQLITE_OK; }
static int pthreadMutexEnd(void){ return SQLITE_OK; }

Changes to src/mutex_w32.c.

85
86
87
88
89
90
91






















92
93
94
95
96
97
98
  SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
  __sync_synchronize();
#else
  MemoryBarrier();
#endif
}























/*
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[] = {
  SQLITE3_MUTEX_INITIALIZER,
  SQLITE3_MUTEX_INITIALIZER,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
  SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
  __sync_synchronize();
#else
  MemoryBarrier();
#endif
}

/*
** Try to provide an atomic compare-and-swap operation on a void pointer,
** needed for initialization only.
*/
void *sqlite3CompareAndSwap(
  void * volatile *pCurVal,
  void *cmpVal,
  void *swapVal
){
#if defined(SQLITE_COMPARE_AND_SWAP)
  return SQLITE_COMPARE_AND_SWAP(pCurVal, cmpVal, swapVal);
#elif SQLITE_PTRSIZE>4
  return (void *)InterlockedCompareExchange64(
      (LONGLONG SQLITE_WIN32_VOLATILE *)pCurVal, (LONGLONG)cmpVal,
      (LONGLONG)swapVal);
#else
  return (void *)InterlockedCompareExchange(
      (LONG SQLITE_WIN32_VOLATILE *)pCurVal, (LONG)cmpVal,
      (LONG)swapVal);
#endif
}

/*
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[] = {
  SQLITE3_MUTEX_INITIALIZER,
  SQLITE3_MUTEX_INITIALIZER,

Changes to src/sqliteInt.h.

2933
2934
2935
2936
2937
2938
2939

2940
2941
2942
2943
2944
2945
2946
....
3184
3185
3186
3187
3188
3189
3190

3191
3192
3193
3194
3195
3196
3197
3198









3199
3200
3201
3202
3203
3204
3205
  int bOpenUri;                     /* True to interpret filenames as URIs */
  int bUseCis;                      /* Use covering indices for full-scans */
  int mxStrlen;                     /* Maximum string length */
  int neverCorrupt;                 /* Database is always well-formed */
  int szLookaside;                  /* Default lookaside buffer size */
  int nLookaside;                   /* Default lookaside buffer count */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */

  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
  sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
  void *pHeap;                      /* Heap storage space */
  int nHeap;                        /* Size of pHeap[] */
  int mnReq, mxReq;                 /* Min and max heap requests sizes */
  sqlite3_int64 szMmap;             /* mmap() space per open file */
  sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
................................................................................
const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
#endif


#ifndef SQLITE_MUTEX_OMIT
  sqlite3_mutex_methods const *sqlite3DefaultMutex(void);
  sqlite3_mutex_methods const *sqlite3NoopMutex(void);

  sqlite3_mutex *sqlite3MutexAlloc(int);
  int sqlite3MutexInit(void);
  int sqlite3MutexEnd(void);
#endif
#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
  void sqlite3MemoryBarrier(void);
#else
# define sqlite3MemoryBarrier();









#endif

sqlite3_int64 sqlite3StatusValue(int);
void sqlite3StatusUp(int, int);
void sqlite3StatusDown(int, int);
void sqlite3StatusSet(int, int);








>







 







>







|
>
>
>
>
>
>
>
>
>







2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
....
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
  int bOpenUri;                     /* True to interpret filenames as URIs */
  int bUseCis;                      /* Use covering indices for full-scans */
  int mxStrlen;                     /* Maximum string length */
  int neverCorrupt;                 /* Database is always well-formed */
  int szLookaside;                  /* Default lookaside buffer size */
  int nLookaside;                   /* Default lookaside buffer count */
  sqlite3_mem_methods m;            /* Low-level memory allocation interface */
  sqlite3_mutex_methods *pMutex;    /* Address of mutex member or zero. */
  sqlite3_mutex_methods mutex;      /* Low-level mutex interface */
  sqlite3_pcache_methods2 pcache2;  /* Low-level page-cache interface */
  void *pHeap;                      /* Heap storage space */
  int nHeap;                        /* Size of pHeap[] */
  int mnReq, mxReq;                 /* Min and max heap requests sizes */
  sqlite3_int64 szMmap;             /* mmap() space per open file */
  sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
................................................................................
const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
#endif


#ifndef SQLITE_MUTEX_OMIT
  sqlite3_mutex_methods const *sqlite3DefaultMutex(void);
  sqlite3_mutex_methods const *sqlite3NoopMutex(void);
  void *sqlite3NoopCompareAndSwap(void * volatile *, void *, void *);
  sqlite3_mutex *sqlite3MutexAlloc(int);
  int sqlite3MutexInit(void);
  int sqlite3MutexEnd(void);
#endif
#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
  void sqlite3MemoryBarrier(void);
#else
# define sqlite3MemoryBarrier()
#endif
#if !defined(SQLITE_MUTEX_OMIT)
# if !defined(SQLITE_MUTEX_NOOP)
   void *sqlite3CompareAndSwap(void * volatile *, void *, void *);
# else
#  define sqlite3CompareAndSwap sqlite3NoopCompareAndSwap
# endif
#else
# define sqlite3CompareAndSwap(x,y,z)
#endif

sqlite3_int64 sqlite3StatusValue(int);
void sqlite3StatusUp(int, int);
void sqlite3StatusDown(int, int);
void sqlite3StatusSet(int, int);