SQLite3.SetDirectory call exposes System.AccessViolationException on Windows 8.1 (WinRT)
In my Windows 8.1 (WinRT) application, I am using SQLite v 3.8.9 with SQLite-net as my database and SemaphoreSlim as my sync tool. It usually works, but sometimes it crashes in SQLite C ++ code when I try to delete a record in a table.
Exception from first chance in (code) in (project name): Microsoft C ++ exception: _com_error in memory location (location).
Delete a record in a table
private static SemaphoreSlim _mutex = new SemaphoreSlim(1,5);
public void DeleteItem(Item item)
{
_mutex.Wait();
using (var connection = new SQLiteConnection(Path))
{
connection.Delete(item);
}
_mutex.Release();
}
SQLite.cs
public SQLiteConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
{
...
#if NETFX_CORE
SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path);
#endif
...
}
Failure occurs when called SQLite3.SetDirectory
.
An exception:
Message:
An attempt was made to read or write protected memory. This is often an indication that other memory is damaged.
StackTrace:
at SQLite.SQLite3.SetDirectory (UInt32 directoryType, String directoryPath)
at SQLite.SQLiteConnection..ctor (String databasePath, SQLiteOpenFlags openFlags, Boolean storeDateTimeAsTicks)
at SQLite.SQLiteConnection..ctor (String databasePath, Boolean storeDateTimeAsTicks)
Question
I guess it must be a Threading issue because it usually works and has intermittent crashes; but I can't find anything.
What could be causing the exception and what can I do to fix it?
I don't think this is corrupted memory, possibly protected, but I'm pretty sure that only one of my threads is accessing it.
source to share
In the end, even though I was sure that only one thread was accessing the SQLite db at a time, it turned out that I had a little bit of code that I didn't expect to be called at the same time; it causedAccessViolationException
To ensure that this problem does not occur in the future, I did the following:
- Moved all SQLite code to another project trying to isolate it.
- Implemented semi-factory pattern in the project to ensure that only one thread is used (this also improved the code)
Factory Database Class
public class DataBaseConnection: SQLite.SQLiteConnection
{
private const string _path = "MySQlitePath";
private static SemaphoreSlim _contextMutex = new SemaphoreSlim(1, 5);
private DataBaseConnection() : base(_path)
{
}
public static DataBaseConnection CreateDataBaseConnection()
{
_contextMutex.Wait();
return new DataBaseConnection();
}
private bool disposed = false;
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if(disposing)
{
}
disposed = true;
base.Dispose(disposing);
_contextMutex.Release();
}
}
Using a factory
using (var connection = DataBaseConnection.CreateDataBaseConnection())
{
connection.Delete(item);
}
Since then I have never seen AccessViolationException
again.
Using multiple DB connections
If you are using multiple connections (i.e. different DB paths), for example:
- MySQlitePath_1
- MySQlitePath_2
- ...
- MySQlitePath_N
You have to use the same synchronization mechanism (in my case SemaphoreSlim
) to ensure that only one SQLite connection is open at any given time; even if they refer to different files.
source to share