diff --git a/extensions/clientprefs/query.cpp b/extensions/clientprefs/query.cpp index 3da7f302..f1883ee3 100644 --- a/extensions/clientprefs/query.cpp +++ b/extensions/clientprefs/query.cpp @@ -92,7 +92,7 @@ void TQueryOp::RunThreadPart() IDBDriver *TQueryOp::GetDriver() { - return m_database->GetDriver(); + return m_driver; } IdentityToken_t *TQueryOp::GetOwner() @@ -114,6 +114,7 @@ TQueryOp::TQueryOp(enum querytype type, int serial) m_type = type; m_serial = serial; m_database = NULL; + m_driver = NULL; m_insertId = -1; m_pResult = NULL; } @@ -123,6 +124,7 @@ TQueryOp::TQueryOp(enum querytype type, Cookie *cookie) m_type = type; m_pCookie = cookie; m_database = NULL; + m_driver = NULL; m_insertId = -1; m_pResult = NULL; m_serial = 0; @@ -131,6 +133,7 @@ TQueryOp::TQueryOp(enum querytype type, Cookie *cookie) void TQueryOp::SetDatabase(IDatabase *db) { m_database = db; + m_driver = m_database->GetDriver(); } bool TQueryOp::BindParamsAndRun() diff --git a/extensions/clientprefs/query.h b/extensions/clientprefs/query.h index 73febd3b..31cdf55d 100644 --- a/extensions/clientprefs/query.h +++ b/extensions/clientprefs/query.h @@ -100,6 +100,7 @@ public: private: IDatabase *m_database; + IDBDriver *m_driver; IQuery *m_pResult; /* Query type */ diff --git a/extensions/sqlite/driver/SqDatabase.h b/extensions/sqlite/driver/SqDatabase.h index 7fb9231f..900fa52b 100644 --- a/extensions/sqlite/driver/SqDatabase.h +++ b/extensions/sqlite/driver/SqDatabase.h @@ -64,6 +64,10 @@ public: bool SetCharacterSet(const char *characterset); public: sqlite3 *GetDb(); + void PrepareForForcedShutdown() + { + m_Persistent = false; + } private: sqlite3 *m_sq3; ke::AutoPtr m_FullLock; diff --git a/extensions/sqlite/driver/SqDriver.cpp b/extensions/sqlite/driver/SqDriver.cpp index 27026183..22769951 100644 --- a/extensions/sqlite/driver/SqDriver.cpp +++ b/extensions/sqlite/driver/SqDriver.cpp @@ -67,6 +67,32 @@ SqDriver::SqDriver() { m_Handle = BAD_HANDLE; m_bThreadSafe = false; + m_bShutdown = false; +} + +// The extension got unloaded. Remove any open database now to avoid a use-after-free +// of g_SqDriver in SqDatabase's destructor. +SqDriver::~SqDriver() +{ + ke::AutoLock lock(&m_OpenLock); + + List::iterator iter; + SqDatabase *sqdb; + for (iter = m_Cache.begin(); iter != m_Cache.end(); iter++) + { + // Don't let SqDatabase try to remove itself from m_Cache + // now that we're gone. + sqdb = (SqDatabase *)(*iter).db; + sqdb->PrepareForForcedShutdown(); + + iter = m_Cache.erase(iter); + } + + if (!m_bShutdown) + { + dbi->RemoveDriver(&g_SqDriver); + Shutdown(); + } } void SqDriver::Initialize() @@ -76,6 +102,7 @@ void SqDriver::Initialize() void SqDriver::Shutdown() { + m_bShutdown = true; if (m_bThreadSafe) { sqlite3_enable_shared_cache(0); diff --git a/extensions/sqlite/driver/SqDriver.h b/extensions/sqlite/driver/SqDriver.h index 77bb3a69..ee35235f 100644 --- a/extensions/sqlite/driver/SqDriver.h +++ b/extensions/sqlite/driver/SqDriver.h @@ -56,6 +56,7 @@ class SqDriver : public IDBDriver { public: SqDriver(); + ~SqDriver(); void Initialize(); void Shutdown(); public: @@ -74,6 +75,7 @@ private: ke::Mutex m_OpenLock; List m_Cache; bool m_bThreadSafe; + bool m_bShutdown; }; extern SqDriver g_SqDriver;