Skip to content

Commit e906fa2

Browse files
committed
Fix issue #194 (second attempt)
- Remove use of SQLITE_EXTRA_INIT and SQLITE_EXTRA_SHUTDOWN - Split sqlite3mc_initialize into 2 parts: 1) initialization of cipher schemes, 2) loading builtin extensions automatically on opening a database - Add SQLite patch to call sqlite3mc_initialize directly from within SQLite's guarded initialization context to avoid race condition - Add SQLite patch to call sqlite3mc_shutdown directly from sqlite3_shutdown
1 parent 120cf51 commit e906fa2

File tree

3 files changed

+36
-33
lines changed

3 files changed

+36
-33
lines changed

scripts/patchsqlite3.sh

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ die() {
1717
# 1) Intercept VFS pragma handling
1818
# 2) Add handling of KEY parameter in ATTACH statements
1919
sed 's/sqlite3_file_control\(.*SQLITE_FCNTL_PRAGMA\)/sqlite3mcFileControlPragma\1/' "$INPUT" \
20-
| sed '/\#endif \/\* SQLITE3\_H \*\//a \ \n\/\* Function prototypes of SQLite3 Multiple Ciphers \*\/\nSQLITE_PRIVATE int sqlite3mcCheckVfs(const char*);\nSQLITE_PRIVATE int sqlite3mcFileControlPragma(sqlite3*, const char*, int, void*);\nSQLITE_PRIVATE int sqlite3mcHandleAttachKey(sqlite3*, const char*, const char*, sqlite3_value*, char**);\nSQLITE_PRIVATE int sqlite3mcHandleMainKey(sqlite3*, const char*);\ntypedef struct PgHdr PgHdrMC;\nSQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdrMC* pPg);\ntypedef struct Pager PagerMC;\nSQLITE_PRIVATE int sqlite3mcPagerHasCodec(PagerMC* pPager);\nSQLITE_PRIVATE void sqlite3mcInitMemoryMethods();\nSQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3*, const char*, sqlite3*, const char*);\nSQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey);' \
20+
| sed '/\#endif \/\* SQLITE3\_H \*\//a \ \n\/\* Function prototypes of SQLite3 Multiple Ciphers \*\/\nSQLITE_PRIVATE int sqlite3mcCheckVfs(const char*);\nSQLITE_PRIVATE int sqlite3mcFileControlPragma(sqlite3*, const char*, int, void*);\nSQLITE_PRIVATE int sqlite3mcHandleAttachKey(sqlite3*, const char*, const char*, sqlite3_value*, char**);\nSQLITE_PRIVATE int sqlite3mcHandleMainKey(sqlite3*, const char*);\ntypedef struct PgHdr PgHdrMC;\nSQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdrMC* pPg);\ntypedef struct Pager PagerMC;\nSQLITE_PRIVATE int sqlite3mcPagerHasCodec(PagerMC* pPager);\nSQLITE_PRIVATE void sqlite3mcInitMemoryMethods();\nSQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3*, const char*, sqlite3*, const char*);\nSQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey);\nSQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db);' \
2121
| sed '/\#define MAX\_PATHNAME 512/c #if SQLITE3MC\_MAX\_PATHNAME \> 512\n#define MAX_PATHNAME SQLITE3MC\_MAX\_PATHNAME\n#else\n#define MAX_PATHNAME 512\n#endif' \
2222
| sed '/pData = pPage->pData;/c \ if( (pData = sqlite3mcPagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;' \
2323
| sed '/pData = p->pData;/c \ if( (pData = sqlite3mcPagerCodec(p))==0 ) return SQLITE_NOMEM;' \
@@ -27,5 +27,8 @@ sed 's/sqlite3_file_control\(.*SQLITE_FCNTL_PRAGMA\)/sqlite3mcFileControlPragma\
2727
| sed '/^ if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;/a \ if( sqlite3mcPagerHasCodec(pPager) != 0 ) return 0;' \
2828
| sed '/^ }else if( USEFETCH(pPager) ){/c \ }else if( USEFETCH(pPager) && sqlite3mcPagerHasCodec(pPager) == 0 ){' \
2929
| sed '/^ if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));/a \\n \/\* Initialize wrapper for memory management.\*\/\n if( rc==SQLITE_OK ) {\n sqlite3mcInitMemoryMethods();\n }\n' \
30+
| sed '/^ sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);/a \ int sqlite3mc_initialize(const char*);\n rc = sqlite3mc_initialize(0);' \
31+
| sed '/^ sqlite3_os_end();/i \ void sqlite3mc_shutdown(void);\n sqlite3mc_shutdown();' \
32+
| sed '/^ SQLITE_EXTRA_AUTOEXT,/!{p;d;};n;a \ sqlite3mc_builtin_extensions,' \
3033
| sed '/Lock the source database handle./i \ \/\* Check whether databases are compatible with backup \*\/\n if (!sqlite3mcIsBackupSupported(pSrcDb, zSrcDb, pDestDb, zDestDb)){\n sqlite3ErrorWithMsg(pDestDb, SQLITE_ERROR, \"backup is not supported with incompatible source and target databases\");\n return NULL;\n }\n' \
3134
| sed '/nRes = sqlite3BtreeGetRequestedReserve(pMain)/a \\n \/\* A VACUUM cannot change the pagesize of an encrypted database. \*\/\n if( db->nextPagesize ){\n extern void sqlite3mcCodecGetKey(sqlite3*, int, void**, int*);\n int nKey;\n char *zKey;\n sqlite3mcCodecGetKey(db, iDb, (void**)&zKey, &nKey);\n if( nKey ) db->nextPagesize = 0;\n }' \

src/sqlite3mc.c

+26-32
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
** Purpose: Amalgamation of the SQLite3 Multiple Ciphers encryption extension for SQLite
44
** Author: Ulrich Telle
55
** Created: 2020-02-28
6-
** Copyright: (c) 2006-2024 Ulrich Telle
6+
** Copyright: (c) 2006-2025 Ulrich Telle
77
** License: MIT
88
*/
99

@@ -37,19 +37,6 @@
3737
#endif
3838
#endif
3939

40-
/*
41-
** Define function for extra initialization and extra shutdown
42-
**
43-
** The extra initialization function registers an extension function
44-
** which will be automatically executed for each new database connection.
45-
**
46-
** The extra shutdown function will be executed on the invocation of sqlite3_shutdown.
47-
** All created multiple ciphers VFSs will be unregistered and destroyed.
48-
*/
49-
50-
#define SQLITE_EXTRA_INIT sqlite3mc_initialize
51-
#define SQLITE_EXTRA_SHUTDOWN sqlite3mc_shutdown
52-
5340
/*
5441
** Declare all internal functions as 'static' unless told otherwise
5542
*/
@@ -538,8 +525,6 @@ sqlite3mcRegisterCipher(const CipherDescriptor* desc, const CipherParams* params
538525
if (!cipherParams)
539526
return SQLITE_NOMEM;
540527

541-
sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN));
542-
543528
/* Check for */
544529
if (globalCipherCount < CODEC_COUNT_MAX)
545530
{
@@ -589,8 +574,6 @@ sqlite3mcRegisterCipher(const CipherDescriptor* desc, const CipherParams* params
589574
rc = SQLITE_NOMEM;
590575
}
591576

592-
sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN));
593-
594577
return rc;
595578
}
596579

@@ -602,7 +585,10 @@ sqlite3mc_register_cipher(const CipherDescriptor* desc, const CipherParams* para
602585
rc = sqlite3_initialize();
603586
if (rc) return rc;
604587
#endif
605-
return sqlite3mcRegisterCipher(desc, params, makeDefault);
588+
sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN));
589+
rc = sqlite3mcRegisterCipher(desc, params, makeDefault);
590+
sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MAIN));
591+
return rc;
606592
}
607593

608594
SQLITE_PRIVATE int
@@ -718,84 +704,92 @@ sqlite3mc_initialize(const char* arg)
718704
{
719705
rc = sqlite3mc_vfs_create(NULL, 1);
720706
}
707+
return rc;
708+
}
709+
710+
SQLITE_PRIVATE int
711+
sqlite3mc_builtin_extensions(sqlite3* db)
712+
{
713+
char* errmsg = NULL;
714+
int rc = SQLITE_OK;
721715

722716
/*
723717
** Register Multi Cipher extension
724718
*/
725719
if (rc == SQLITE_OK)
726720
{
727-
rc = sqlite3_auto_extension((void(*)(void)) mcRegisterCodecExtensions);
721+
rc = mcRegisterCodecExtensions(db, &errmsg, NULL);
728722
}
729723
#ifdef SQLITE_ENABLE_EXTFUNC
730724
if (rc == SQLITE_OK)
731725
{
732-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_extfunc_init);
726+
rc = sqlite3_extfunc_init(db, &errmsg, NULL);
733727
}
734728
#endif
735729
#ifdef SQLITE_ENABLE_CSV
736730
if (rc == SQLITE_OK)
737731
{
738-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_csv_init);
732+
rc = sqlite3_csv_init(db, &errmsg, NULL);
739733
}
740734
#endif
741735
#ifdef SQLITE_ENABLE_VSV
742736
if (rc == SQLITE_OK)
743737
{
744-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_vsv_init);
738+
rc = sqlite3_vsv_init(db, &errmsg, NULL);
745739
}
746740
#endif
747741
#ifdef SQLITE_ENABLE_SHA3
748742
if (rc == SQLITE_OK)
749743
{
750-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_shathree_init);
744+
rc = sqlite3_shathree_init(db, &errmsg, NULL);
751745
}
752746
#endif
753747
#ifdef SQLITE_ENABLE_CARRAY
754748
if (rc == SQLITE_OK)
755749
{
756-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_carray_init);
750+
rc = sqlite3_carray_init(db, &errmsg, NULL);
757751
}
758752
#endif
759753
#ifdef SQLITE_ENABLE_FILEIO
760754
if (rc == SQLITE_OK)
761755
{
762-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_fileio_init);
756+
rc = sqlite3_fileio_init(db, &errmsg, NULL);
763757
}
764758
#endif
765759
#ifdef SQLITE_ENABLE_SERIES
766760
if (rc == SQLITE_OK)
767761
{
768-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_series_init);
762+
rc = sqlite3_series_init(db, &errmsg, NULL);
769763
}
770764
#endif
771765
#ifdef SQLITE_ENABLE_UUID
772766
if (rc == SQLITE_OK)
773767
{
774-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_uuid_init);
768+
rc = sqlite3_uuid_init(db, &errmsg, NULL);
775769
}
776770
#endif
777771
#ifdef SQLITE_ENABLE_REGEXP
778772
if (rc == SQLITE_OK)
779773
{
780-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_regexp_init);
774+
rc = sqlite3_regexp_init(db, &errmsg, NULL);
781775
}
782776
#endif
783777
#ifdef SQLITE_ENABLE_COMPRESS
784778
if (rc == SQLITE_OK)
785779
{
786-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_compress_init);
780+
rc = sqlite3_compress_init(db, &errmsg, NULL);
787781
}
788782
#endif
789783
#ifdef SQLITE_ENABLE_SQLAR
790784
if (rc == SQLITE_OK)
791785
{
792-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_sqlar_init);
786+
rc = sqlite3_sqlar_init(db, &errmsg, NULL);
793787
}
794788
#endif
795789
#ifdef SQLITE_ENABLE_ZIPFILE
796790
if (rc == SQLITE_OK)
797791
{
798-
rc = sqlite3_auto_extension((void(*)(void)) sqlite3_zipfile_init);
792+
rc = sqlite3_zipfile_init(db, &errmsg, NULL);
799793
}
800794
#endif
801795
return rc;

src/sqlite3patched.c

+6
Original file line numberDiff line numberDiff line change
@@ -14045,6 +14045,7 @@ SQLITE_PRIVATE int sqlite3mcPagerHasCodec(PagerMC* pPager);
1404514045
SQLITE_PRIVATE void sqlite3mcInitMemoryMethods();
1404614046
SQLITE_PRIVATE int sqlite3mcIsBackupSupported(sqlite3*, const char*, sqlite3*, const char*);
1404714047
SQLITE_PRIVATE void sqlite3mcCodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey);
14048+
SQLITE_PRIVATE int sqlite3mc_builtin_extensions(sqlite3* db);
1404814049

1404914050
/************** End of sqlite3.h *********************************************/
1405014051
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -181668,6 +181669,7 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
181668181669
#ifdef SQLITE_EXTRA_AUTOEXT
181669181670
SQLITE_EXTRA_AUTOEXT,
181670181671
#endif
181672+
sqlite3mc_builtin_extensions,
181671181673
};
181672181674

181673181675
#ifndef SQLITE_AMALGAMATION
@@ -181885,6 +181887,8 @@ SQLITE_API int sqlite3_initialize(void){
181885181887
if( rc==SQLITE_OK ){
181886181888
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
181887181889
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
181890+
int sqlite3mc_initialize(const char*);
181891+
rc = sqlite3mc_initialize(0);
181888181892
sqlite3MemoryBarrier();
181889181893
sqlite3GlobalConfig.isInit = 1;
181890181894
#ifdef SQLITE_EXTRA_INIT
@@ -181959,6 +181963,8 @@ SQLITE_API int sqlite3_shutdown(void){
181959181963
void SQLITE_EXTRA_SHUTDOWN(void);
181960181964
SQLITE_EXTRA_SHUTDOWN();
181961181965
#endif
181966+
void sqlite3mc_shutdown(void);
181967+
sqlite3mc_shutdown();
181962181968
sqlite3_os_end();
181963181969
sqlite3_reset_auto_extension();
181964181970
sqlite3GlobalConfig.isInit = 0;

0 commit comments

Comments
 (0)