diff -r 667e88a979d7 -r 31a8f755b7fe persistentstorage/sql/SRC/Server/SqlSrvDatabase.cpp --- a/persistentstorage/sql/SRC/Server/SqlSrvDatabase.cpp Mon Mar 15 12:46:30 2010 +0200 +++ b/persistentstorage/sql/SRC/Server/SqlSrvDatabase.cpp Thu Apr 01 00:19:42 2010 +0300 @@ -391,6 +391,7 @@ TSqlCompactDbPair compactDbPair; while(compactDbIt.Next(compactDbPair)) { + __SQLASSERT(compactDbPair.iData, ESqlPanicInvalidObj); ::SqlServer().Compactor().ReleaseEntry(*compactDbPair.iData); } iCompactDbMap.Close(); @@ -405,6 +406,37 @@ //The security policy map owns iSecureDbName and iSecurityPolicy and is responsible for //iSecureDbName and iSecurityPolicy destruction. } + //The next step of the "resource release" process is to walk over iAttachDbMap entries, get the data part of + //the found TSqlAttachDbPair objects, which is secure database name used as a key in iSecurityMap, and remove + //the related entry from iSecurityMap. If the database is closed in normal circumstances, the iAttachDbMap + //has no entries. But if the database client forgets to detach the used attached databases or if the Detach() call + //fails (for example, with KErrNoMemory error), then at this point iAttachDbMap has one or more entries. + //That means there are still some attached databases to this connection. This is not a problem, SQLite will take + //care of them. The problem is that there are related entries in iSecurityMap map, owned by CSqlServer object, + //and they won't be removed from the map till CSqlServer object is alive. This causes problems in OOM tests and in + //real life of the device. + //For example, one database client opens "c:[11111111]a.db" and attaches "c:[11111111]b.db": + // - c:[11111111]a.db database has been opened successfully. iSecurityMap has 1 entry: + // {"c:[11111111]a.db", }. + // - c:[11111111]b.db is attached to c:[11111111]a.db with name "db2". There will be 1 entry in iAttachDbMap: + // {"db2", "c:[11111111]a.db"} + // and a new entry will be added to iSecurityMap: + // {"c:[11111111]b.db", }. 2 entries in total in iSecurityMap. + // - The database client attempts to detach the attached database but the opertaion fails during the execution + // of the DETACH sql statement. Both maps are intact. + // - The database client attempts to close the database. The previous implementation of CSqlSrvDatabase::~CSqlSrvDatabase() + // would only remove "c:[11111111]a.db" entry from iSecurityMap and close the iAttachDbMap map. + // The result: no opened or attached databases but there will be one entry in iSecurityMap: "c:[11111111]b.db". + // OOM tests will report a memory leak in this case. On a real device, if "c:[11111111]b.db" gets deleted and + // recreated again, unexpected memory leak will occur in CSqlSrvDatabase::ConstructCreateSecureL() because + // the code there "expects" that is the first time when a "c:[11111111]b.db" entry is added to iSecurityMap. + TSqlAttachDbMapIterator it(iAttachDbMap); + TSqlAttachDbPair attachDbPair; + while(it.Next(attachDbPair)) + { + __SQLASSERT(attachDbPair.iData, ESqlPanicInvalidObj); + ::SqlServer().SecurityMap().Remove(attachDbPair.iData); + } iAttachDbMap.Close(); ::CloseDbHandle(iDbHandle); } @@ -1042,6 +1074,7 @@ aMapKey = ::CreateStrCopyLC(aMapKey); CSqlSecurityPolicy* securityPolicy = aAttachedDb ? ::LoadAttachedDbSecurityPolicyLC(aFileData) : ::LoadDbSecurityPolicyLC(iDbHandle); + __SQLASSERT(!::SqlServer().SecurityMap().Entry(aMapKey), ESqlPanicObjExists); __SQLLEAVE_IF_ERROR(::SqlServer().SecurityMap().Insert(aMapKey, securityPolicy)); CleanupStack::Pop(2);//iSecurityMap owns aMapKey and securityPolicy objects aSecurityPolicy = securityPolicy; @@ -1115,6 +1148,7 @@ const TUint8* mapKey = ::CreateStrCopyLC(iFileNameBuf); const TUint8* mapData = SecurityMapKeyL(aDbFileName); mapData = ::CreateStrCopyLC(mapData); + __SQLASSERT(!iAttachDbMap.Entry(mapKey), ESqlPanicObjExists); __SQLLEAVE_IF_ERROR(iAttachDbMap.Insert(mapKey, mapData)); CleanupStack::Pop(2);//iAttachDbMap owns mapKey amd mapData. } @@ -1326,6 +1360,7 @@ HBufC* data = aDbFileName.Alloc(); if(key && data) { + __SQLASSERT(!iCompactDbMap.Entry(key), ESqlPanicObjExists); err = iCompactDbMap.Insert(key, data);//returns the index of the new entry } if(err < 0) //If either "key" or "data" or both is NULL, then "err" is KErrNoMemory and the next "if" will be executed. @@ -1438,6 +1473,7 @@ CleanupStack::PushL(aSecurityPolicy); const TUint8* mapKey = SecurityMapKeyL(aFileData.FileName()); mapKey = ::CreateStrCopyLC(mapKey); + __SQLASSERT(!::SqlServer().SecurityMap().Entry(mapKey), ESqlPanicObjExists); __SQLLEAVE_IF_ERROR(::SqlServer().SecurityMap().Insert(mapKey, aSecurityPolicy)); CleanupStack::Pop(2);//iSecurityMap owns mapKey and aSecurityPolicy. iSecureDbName = mapKey;