Barnstokkr
Barnstokkr

Reputation: 3129

Calling SQLite3.SetDirectory gives a System.AccessViolationException on Windows 8.1 (WinRT)

In my Windows 8.1 (WinRT) app I am using SQLite v 3.8.9 with SQLite-net as my database, and SemaphoreSlim as my synchronization enforcer. It usually works, but sometimes it crashes in the SQLite's C++ code when I try to delete a table entry.

First-chance exception at (code) in (project name): Microsoft C++ exception: _com_error at memory location (location).

Delete table entry

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
    ...
}

The crash happens when SQLite3.SetDirectory is called.

Exception:

System.AccessViolationException

Message:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

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 am guessing that this must be a Threading issue because it usually works and has irregular crashes; but I am unable to find anything.

What can be the cause of the exception and what can I do to fix it?

I do not think it is corrupted memory, maybe protected, but I am fairly sure that only one of my threads are accessing it

Upvotes: 3

Views: 1138

Answers (1)

Barnstokkr
Barnstokkr

Reputation: 3129

In the end, even though I was confident that only one thread was accessing the SQLite db at a time, it turned out that I had some minor code that I didn't expect was called at the same time; this caused the AccessViolationException

To ensure that this problem does not arise in the future, I did the following:

  • Moved the whole SQLite code to a different project in an attempt to isolate it.
  • Implemented a semi-factory pattern in the project to ensure that only one thread uses it (this also made the code look better)

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 the factory

using (var connection = DataBaseConnection.CreateDataBaseConnection())
{
     connection.Delete(item);
}

Since using this, I've never seen the AccessViolationException again.


Using Multiple DB connections

If you are using Multiple Connections (i.e. different DB paths) such as:

  • MySQlitePath_1
  • MySQlitePath_2
  • ...
  • MySQlitePath_N

You should use the same Synchronization Mechanism (in my case SemaphoreSlim) throughout to ensure only one SQLite Connection is open at any given time; even though they are accessing different files.

Upvotes: 1

Related Questions