From: mistachkin Date: Fri, 11 Sep 2015 05:06:15 +0000 (+0000) Subject: Enhance mutex initialization to prevent possible race conditions between sqlite3_init... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8bdc914af3dfd8a4092357c28f8dfd0ec9af2bf4;p=thirdparty%2Fsqlite.git 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. FossilOrigin-Name: f6a8f577957769171acd72df3cc9aa5ad474d84b --- diff --git a/manifest b/manifest index 253acb782d..93a50e6168 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\ssqlite3_value_subtype()\sand\ssqlite3_result_subtype()\ndocumentation\sand\sto\stest\scases\sfor\sjson1\sdealing\swith\sthose\sinterfaces. -D 2015-09-11T01:22:41.498 +C Enhance\smutex\sinitialization\sto\sprevent\spossible\srace\sconditions\sbetween\ssqlite3_initialize()\sand\ssqlite3_config().\s\sAlso,\sre-check\ssqlite3GlobalConfig.isInit\safter\sthe\smutex\ssubsystem\shas\sbeen\sinitialized. +D 2015-09-11T05:06:15.636 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -296,7 +296,7 @@ F src/expr.c 3a76afcdac925294c39903b7002ddb9e5fd29863 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 83e1baba999bed3144ea5a2143fc922edf51135f F src/func.c ecdd69ec6a1e406f04cc73324be2ebbf6354197f -F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 +F src/global.c d824163680839be79b53204105a78e5be5d4ac4a F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 @@ -305,7 +305,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012 F src/loadext.c f0b66d28e377fd6c6d36cc9d92df1ff251ebee44 -F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54 +F src/main.c ff612656f1c0e4676f5da919ecc8e39a8d7b857a F src/malloc.c 3a37ce6979a40f499d8cea9e9ab4e8517854d35d F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987 @@ -314,11 +314,11 @@ F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 -F src/mutex.c a39809c6c33f1ebc9cc781186c338ad90433e1e7 +F src/mutex.c de4293e5feb5dae2a1786283a2ae971e899f6745 F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85 -F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 -F src/mutex_unix.c 7762c8ec907379204f2ed751a0e33663ab1c14d7 -F src/mutex_w32.c 2e025e6642eaf27597403690980f560d1a91f62c +F src/mutex_noop.c f03e26ba8258399da23b51234f6b6a97197c1900 +F src/mutex_unix.c a72043f2560147d8e85fe48a6aef682896deb3a0 +F src/mutex_w32.c a784f7c278770e80f951be1a84c0d5bb227748d9 F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf @@ -345,7 +345,7 @@ F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42 F src/sqlite.h.in dbaf8c3796e80221de4395b5f4f872abddb5f89f F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 64350bf36833a56ad675e27392a913f417c5c308 -F src/sqliteInt.h 788dc0ea7ba32ec9fec06c628c1792d7b4753d86 +F src/sqliteInt.h d7b2c30947a49a7538f24c0dca253c0e456c849c F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -1386,7 +1386,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P db4152aef2253ed2a33e3cad01e0c6758e03f900 -R 1bba7f6a951d63c0429f61e7df8f5c7d -U drh -Z 186760bb5fa5f9976b74dfde02dde033 +P d6cadbe9fefce9a7af6b2d0cb83362f967d7d89a +R 4ed3244c4cf92a71208fc6495549ac56 +T *branch * mutexInitCmpSwap +T *sym-mutexInitCmpSwap * +T -sym-trunk * +U mistachkin +Z b1c2ac01d3f97f9d2891430a375f1a69 diff --git a/manifest.uuid b/manifest.uuid index 11d07fd29a..dcef74b2c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d6cadbe9fefce9a7af6b2d0cb83362f967d7d89a \ No newline at end of file +f6a8f577957769171acd72df3cc9aa5ad474d84b \ No newline at end of file diff --git a/src/global.c b/src/global.c index ef4fe56ae1..f995e9d708 100644 --- a/src/global.c +++ b/src/global.c @@ -174,6 +174,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { 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 */ diff --git a/src/main.c b/src/main.c index 575cad92c5..9e842d9ca8 100644 --- a/src/main.c +++ b/src/main.c @@ -171,7 +171,13 @@ int sqlite3_initialize(void){ */ MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(pMaster); - sqlite3GlobalConfig.isMutexInit = 1; + 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(); } @@ -384,8 +390,15 @@ int sqlite3_config(int op, ...){ #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*); + /* 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 diff --git a/src/mutex.c b/src/mutex.c index a2e4e6387a..63efefe923 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -22,39 +22,50 @@ ** allocate a mutex while the system is uninitialized. */ static SQLITE_WSD int mutexIsInit = 0; -#endif /* SQLITE_DEBUG */ +#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 = SQLITE_OK; - if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){ + 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; - 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; + mutexCopy(&sqlite3GlobalConfig.mutex, pFrom); sqlite3MemoryBarrier(); - pTo->xMutexAlloc = pFrom->xMutexAlloc; } rc = sqlite3GlobalConfig.mutex.xMutexInit(); diff --git a/src/mutex_noop.c b/src/mutex_noop.c index ecc84b4a94..0d954dfce1 100644 --- a/src/mutex_noop.c +++ b/src/mutex_noop.c @@ -29,6 +29,28 @@ #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. diff --git a/src/mutex_unix.c b/src/mutex_unix.c index 78fba1d81f..c205086df0 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -86,11 +86,39 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){ void sqlite3MemoryBarrier(void){ #if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; -#elif defined(__GNUC__) +#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. */ diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 90be07db2d..0fa752d999 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -90,6 +90,28 @@ void sqlite3MemoryBarrier(void){ #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. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 98cbca5193..d1c81f1f13 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2937,6 +2937,7 @@ struct Sqlite3Config { 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 */ @@ -3188,6 +3189,7 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); #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); @@ -3195,7 +3197,16 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); #if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP) void sqlite3MemoryBarrier(void); #else -# define sqlite3MemoryBarrier(); +# 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);