System.AccessViolationException与SQLite [英] System.AccessViolationException with SQLite

查看:107
本文介绍了System.AccessViolationException与SQLite的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在,我正在处理此错误:

Right now, I'm dealing with this error:

An unhandled exception of type 'System.AccessViolationException' occurred in Unknown Module.

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

没有调用堆栈,因为没有为抛出该DLL的模块加载任何模块。我有一个枚举整个注册表并尝试将所有键/值保存到SQLite数据库文件作为注册表快照的应用程序。从某种意义上来说,它不是贪婪的,如果它无法访问某些密钥,则这些密钥将被丢弃,等等。

There is no call stack for it since no module was loaded for the DLL that threw it. I have an application that enumerates the entire registry and tries to save all keys/values to an SQLite database file, as a registry snapshot. Its not greedy in the sense that if it can't get access to some keys, those keys are discarded, etc.:

using Microsoft.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RegistryMonitor
{
    class Program
    {

        static void Main(string[] args)
        {
            GenerateRegistrySnapshot("SnapshotOne.sqlite");
            Console.ReadLine();   
        }

        static void GenerateRegistrySnapshot(string filename)
        {
            File.Delete(filename);
            SQLiteConnection.CreateFile(filename);
            using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + filename + ";Version=3;"))
            {
                connection.Open();
                CreateTable(connection);
                Stopwatch watch = new Stopwatch();
                Console.WriteLine("Started walking the registry into file {0}.", filename);
                watch.Start();
                transaction = connection.BeginTransaction();
                WalkTheRegistryAndPopulateTheSnapshot(connection);
                try
                {
                    transaction.Commit();
                    transaction.Dispose();
                }
                catch { }
                Console.WriteLine("Finished walking the registry and populating the snapshot.");
                watch.Stop();
                Console.WriteLine("Finished walking the registry in {0} seconds.", watch.Elapsed.TotalSeconds);
                connection.Close();
            }
        }

        static void CreateTable(SQLiteConnection connection)
        {
            SQLiteCommand command = new SQLiteCommand("CREATE TABLE Snapshot (ID INTEGER PRIMARY KEY AUTOINCREMENT, RegistryView INTEGER NULL, Path TEXT NULL, IsKey BOOLEAN NULL, RegistryValueKind INTEGER NULL, ValueName TEXT NULL, Value BLOB NULL, HashValue INTEGER NULL)", connection);
            command.ExecuteNonQuery();
        }

        static SQLiteTransaction transaction = null;
        static int insertions = 0;
        static object transactionLock = new object();

        static void AddEntry(SQLiteConnection connection, RegistryPath path)
        {
            SQLiteCommand command = new SQLiteCommand("INSERT INTO Snapshot (RegistryView, Path, IsKey, RegistryValueKind, ValueName, Value, HashValue) VALUES (@RegistryView, @Path, @IsKey, @RegistryValueKind, @ValueName, @Value, @HashValue)", connection);
            command.Parameters.Add("@RegistryView", DbType.Int32).Value = path.View;
            command.Parameters.Add("@Path", DbType.String).Value = path.Path;
            command.Parameters.Add("@IsKey", DbType.Boolean).Value = path.IsKey;
            command.Parameters.Add("@RegistryValueKind", DbType.Int32).Value = path.ValueKind;
            command.Parameters.Add("@ValueName", DbType.String).Value = path.ValueName;
            command.Parameters.Add("@Value", DbType.Object).Value = path.Value;
            command.Parameters.Add("@HashValue", DbType.Int32).Value = path.HashValue;
            command.ExecuteNonQuery();
            lock (transactionLock)
            {
                insertions++;
                if (insertions > 100000)
                {
                    insertions = 0;
                    transaction.Commit();
                    transaction.Dispose();
                    transaction = connection.BeginTransaction();
                }
            }
        }

        private static void WalkTheRegistryAndPopulateTheSnapshot(SQLiteConnection connection)
        {
            List<ManualResetEvent> handles = new List<ManualResetEvent>();
            foreach (RegistryHive hive in Enum.GetValues(typeof(RegistryHive)))
            {
                foreach (RegistryView view in Enum.GetValues(typeof(RegistryView)).Cast<RegistryView>().ToList().Where(x => x != RegistryView.Default))
                {
                    ManualResetEvent manualResetEvent = new ManualResetEvent(false);
                    handles.Add(manualResetEvent);
                    new Thread(() =>
                    {
                        Console.WriteLine("Walking hive {0} in registry view {1}.", hive.ToString(), view.ToString());
                        WalkKey(connection, view, RegistryKey.OpenBaseKey(hive, view));
                        Console.WriteLine("Finished walking hive {0} in registry view {1}.", hive.ToString(), view.ToString());
                        manualResetEvent.Set();
                        Console.WriteLine("Finished setting event for hive {0} in registry view {1}.", hive.ToString(), view.ToString());
                    }).Start();
                }
            }
            ManualResetEvent.WaitAll(handles.ToArray());
        }

        private static void WalkKey(SQLiteConnection connection, RegistryView view, RegistryKey key)
        {
            RegistryPath path = new RegistryPath(view, key.Name);
            AddEntry(connection, path);
            string[] valueNames = null;
            try
            {
                valueNames = key.GetValueNames();
            }
            catch { }
            if (valueNames != null)
            {
                foreach (string valueName in valueNames)
                {
                    RegistryValueKind valueKind = RegistryValueKind.Unknown;
                    try
                    {
                        valueKind = key.GetValueKind(valueName);
                    }
                    catch { }
                    object value = key.GetValue(valueName);
                    RegistryPath pathForValue = new RegistryPath(view, key.Name, valueKind, valueName, value);
                    AddEntry(connection, pathForValue);
                }
            }
            string[] subKeyNames = null;
            try
            {
                subKeyNames = key.GetSubKeyNames();
            }
            catch { }
            if (subKeyNames != null)
            {
                foreach (string subKeyName in subKeyNames)
                {
                    try
                    {
                        WalkKey(connection, view, key.OpenSubKey(subKeyName));
                    }
                    catch { }
                }
            }
        }

        class RegistryPath
        {
            public RegistryView View;
            public string Path;
            public bool IsKey;
            public RegistryValueKind ValueKind;
            public string ValueName;
            public object Value;
            public int HashValue;

            public RegistryPath(RegistryView view, string path)
            {
                View = view;
                Path = path;
                IsKey = true;
                HashValue = (view.GetHashCode() ^ path.GetHashCode()).GetHashCode();
            }

            public RegistryPath(RegistryView view, string path, RegistryValueKind valueKind, string valueName, object value)
            {
                View = view;
                Path = path;
                IsKey = false;
                ValueKind = valueKind;
                ValueName = valueName;
                Value = value;
                if (value != null)
                {
                    HashValue = (view.GetHashCode() ^ path.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode() ^ value.GetHashCode()).GetHashCode();
                }
                else
                {
                    HashValue = (view.GetHashCode() ^ path.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode()).GetHashCode();
                }
            }
        }
    }
}

由于应用程序是线程化的,因此AddEntry在事务周围使用并发性。最初,我没有使用插入计数器,但是后来我意识到,由于我的应用程序是针对x86构建的,并且使用.NET Framework 4.5.1,因此只要该应用程序具有近2GB的RAM,它就会完全冻结,这导致我相信这是由于x86系统上SQLite的另一个问题所致,例如x86上.NET中集合的2GB RAM限制。我使用插入计数器尝试如此频繁地提交事务,以免遇到较大的事务队列。现在,即使我做到了,仍然留下了AccessViolationException。我不确定是什么原因造成的。有人有任何线索吗?完整的代码在这里,您可以将其复制并粘贴到控制台应用程序中,然后亲自查看。我只是希望您拥有一个相当强大的注册表。非常感谢您的帮助;

Since the application is threaded, AddEntry uses concurrency around transactions. Originally, I did not use an insertions counter, but then I soon realized that, since my application is built for x86 and using .NET Framework 4.5.1, whenever the application had almost 2GB of RAM, it would totally freeze up, leading me to believe that its due to another issue in SQLite on x86 systems, like for example the 2GB RAM limit of collections in .NET on x86. I used an insertions counter to try to commit transactions ever so often in order to not hit a large transaction queue. Now, even though I did that, I'm still left with this AccessViolationException. I'm not sure what causes it. Does anyone have any clues? The entire code is here, you can copy and paste it into a console application and see for yourself. I just hope you have a fairly beefy registry. Help is greatly appreciated; thanks in advance!

推荐答案

CL 值得为此荣誉;他提到 SQLite可以安全地由多个线程使用,前提是两个或多个以上没有同时使用单个数据库连接线程

CL. deserves credit for this; he mentioned that SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.

此方法解决了问题:

using Microsoft.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RegistryMonitor
{
    class Program
    {

        static void Main(string[] args)
        {
            GenerateRegistrySnapshot("SnapshotOne.sqlite");
            Console.ReadLine();   
        }

        static void GenerateRegistrySnapshot(string filename)
        {
            File.Delete(filename);
            SQLiteConnection.CreateFile(filename);
            bool finished = false;
            ConcurrentQueue<RegistryPath> queue = new ConcurrentQueue<RegistryPath>();
            Thread worker = new Thread(() =>
            {
                using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + filename + ";Version=3;"))
                {
                    connection.Open();
                    CreateTable(connection);
                    SQLiteTransaction transaction = connection.BeginTransaction();
                    RegistryPath path;
                    while (!finished)
                    {
                        while (queue.TryDequeue(out path))
                        {
                            AddEntry(connection, path);
                        }
                        Thread.Sleep(100);
                    }
                    transaction.Commit();
                    transaction.Dispose();
                    connection.Close();
                }
            });
            worker.Start();
            Stopwatch watch = new Stopwatch();
            Console.WriteLine("Started walking the registry into file {0}.", filename);
            watch.Start();
            WalkTheRegistryAndPopulateTheSnapshot(queue);
            finished = true;
            worker.Join();
            watch.Stop();
            Console.WriteLine("Finished walking the registry in {0} seconds.", watch.Elapsed.TotalSeconds);
        }

        static void CreateTable(SQLiteConnection connection)
        {
            SQLiteCommand command = new SQLiteCommand("CREATE TABLE Snapshot (ID INTEGER PRIMARY KEY AUTOINCREMENT, RegistryView INTEGER NULL, Path TEXT NULL, IsKey BOOLEAN NULL, RegistryValueKind INTEGER NULL, ValueName TEXT NULL, Value BLOB NULL, HashValue INTEGER NULL)", connection);
            command.ExecuteNonQuery();
        }

        static void AddEntry(SQLiteConnection connection, RegistryPath path)
        {
            SQLiteCommand command = new SQLiteCommand("INSERT INTO Snapshot (RegistryView, Path, IsKey, RegistryValueKind, ValueName, Value, HashValue) VALUES (@RegistryView, @Path, @IsKey, @RegistryValueKind, @ValueName, @Value, @HashValue)", connection);
            command.Parameters.Add("@RegistryView", DbType.Int32).Value = path.View;
            command.Parameters.Add("@Path", DbType.String).Value = path.Path;
            command.Parameters.Add("@IsKey", DbType.Boolean).Value = path.IsKey;
            command.Parameters.Add("@RegistryValueKind", DbType.Int32).Value = path.ValueKind;
            command.Parameters.Add("@ValueName", DbType.String).Value = path.ValueName;
            command.Parameters.Add("@Value", DbType.Object).Value = path.Value;
            command.Parameters.Add("@HashValue", DbType.Int32).Value = path.HashValue;
            command.ExecuteNonQuery();
        }

        private static void WalkTheRegistryAndPopulateTheSnapshot(ConcurrentQueue<RegistryPath> queue)
        {
            List<ManualResetEvent> handles = new List<ManualResetEvent>();
            foreach (RegistryHive hive in Enum.GetValues(typeof(RegistryHive)))
            {
                foreach (RegistryView view in Enum.GetValues(typeof(RegistryView)).Cast<RegistryView>().ToList().Where(x => x != RegistryView.Default))
                {
                    ManualResetEvent manualResetEvent = new ManualResetEvent(false);
                    handles.Add(manualResetEvent);
                    new Thread(() =>
                    {
                        WalkKey(queue, view, RegistryKey.OpenBaseKey(hive, view));
                        manualResetEvent.Set();
                    }).Start();
                }
            }
            ManualResetEvent.WaitAll(handles.ToArray());
        }

        private static void WalkKey(ConcurrentQueue<RegistryPath> queue, RegistryView view, RegistryKey key)
        {
            RegistryPath path = new RegistryPath(view, key.Name);
            queue.Enqueue(path);
            string[] valueNames = null;
            try
            {
                valueNames = key.GetValueNames();
            }
            catch { }
            if (valueNames != null)
            {
                foreach (string valueName in valueNames)
                {
                    RegistryValueKind valueKind = RegistryValueKind.Unknown;
                    try
                    {
                        valueKind = key.GetValueKind(valueName);
                    }
                    catch { }
                    object value = key.GetValue(valueName);
                    RegistryPath pathForValue = new RegistryPath(view, key.Name, valueKind, valueName, value);
                    queue.Enqueue(pathForValue);
                }
            }
            string[] subKeyNames = null;
            try
            {
                subKeyNames = key.GetSubKeyNames();
            }
            catch { }
            if (subKeyNames != null)
            {
                foreach (string subKeyName in subKeyNames)
                {
                    try
                    {
                        WalkKey(queue, view, key.OpenSubKey(subKeyName));
                    }
                    catch { }
                }
            }
        }

        class RegistryPath
        {
            public RegistryView View;
            public string Path;
            public bool IsKey;
            public RegistryValueKind ValueKind;
            public string ValueName;
            public object Value;
            public int HashValue;

            public RegistryPath(RegistryView view, string path)
            {
                View = view;
                Path = path;
                IsKey = true;
                HashValue = (view.GetHashCode() ^ path.GetHashCode()).GetHashCode();
            }

            public RegistryPath(RegistryView view, string path, RegistryValueKind valueKind, string valueName, object value)
            {
                View = view;
                Path = path;
                IsKey = false;
                ValueKind = valueKind;
                ValueName = valueName;
                Value = value;
                if (value != null)
                {
                    HashValue = (view.GetHashCode() ^ path.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode() ^ value.GetHashCode()).GetHashCode();
                }
                else
                {
                    HashValue = (view.GetHashCode() ^ path.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode()).GetHashCode();
                }
            }
        }
    }
}

编辑:甚至可能是这样的事情(非常少的内存使用)...

Edit: Possibly even something like this (very minimal memory usage)...

using Microsoft.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RegistryMonitor
{
    class Program
    {

        static void Main(string[] args)
        {
            GenerateRegistrySnapshot("Snapshot.sqlite");
            Console.ReadLine();   
        }

        static object writeLock = new object();
        static AutoResetEvent writeReady = new AutoResetEvent(false);
        static AutoResetEvent writeCompleted = new AutoResetEvent(false);
        static RegistryPath pathToWrite;

        static void GenerateRegistrySnapshot(string filename)
        {
            File.Delete(filename);
            SQLiteConnection.CreateFile(filename);
            bool finished = false;
            Thread worker = new Thread(() =>
            {
                using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + filename + ";Version=3;"))
                {
                    connection.Open();
                    CreateTable(connection);
                    SQLiteTransaction transaction = connection.BeginTransaction();
                    while (!finished)
                    {
                        writeReady.WaitOne();
                        if (finished)
                        {
                            break;
                        }
                        AddEntry(connection, pathToWrite);
                        writeCompleted.Set();
                    }
                    transaction.Commit();
                    transaction.Dispose();
                    connection.Close();
                }
            });
            worker.Start();
            Stopwatch watch = new Stopwatch();
            Console.WriteLine("Started walking the registry into file {0}.", filename);
            watch.Start();
            WalkTheRegistryAndPopulateTheSnapshot();
            finished = true;
            writeReady.Set();
            worker.Join();
            watch.Stop();
            Console.WriteLine("Finished walking the registry in {0} seconds.", watch.Elapsed.TotalSeconds);
        }

        static void CreateTable(SQLiteConnection connection)
        {
            SQLiteCommand command = new SQLiteCommand("CREATE TABLE Snapshot (ID INTEGER PRIMARY KEY AUTOINCREMENT, RegistryView INTEGER NULL, Path TEXT NULL, IsKey BOOLEAN NULL, RegistryValueKind INTEGER NULL, ValueName TEXT NULL, Value BLOB NULL, HashValue INTEGER NULL)", connection);
            command.ExecuteNonQuery();
        }

        static void AddEntry(SQLiteConnection connection, RegistryPath path)
        {
            SQLiteCommand command = new SQLiteCommand("INSERT INTO Snapshot (RegistryView, Path, IsKey, RegistryValueKind, ValueName, Value, HashValue) VALUES (@RegistryView, @Path, @IsKey, @RegistryValueKind, @ValueName, @Value, @HashValue)", connection);
            command.Parameters.Add("@RegistryView", DbType.Int32).Value = path.View;
            command.Parameters.Add("@Path", DbType.String).Value = path.Path;
            command.Parameters.Add("@IsKey", DbType.Boolean).Value = path.IsKey;
            command.Parameters.Add("@RegistryValueKind", DbType.Int32).Value = path.ValueKind;
            command.Parameters.Add("@ValueName", DbType.String).Value = path.ValueName;
            command.Parameters.Add("@Value", DbType.Object).Value = path.Value;
            command.Parameters.Add("@HashValue", DbType.Int32).Value = path.HashValue;
            command.ExecuteNonQuery();
        }

        private static void WalkTheRegistryAndPopulateTheSnapshot()
        {
            List<ManualResetEvent> handles = new List<ManualResetEvent>();
            foreach (RegistryHive hive in Enum.GetValues(typeof(RegistryHive)))
            {
                foreach (RegistryView view in Enum.GetValues(typeof(RegistryView)).Cast<RegistryView>().ToList().Where(x => x != RegistryView.Default))
                {
                    ManualResetEvent manualResetEvent = new ManualResetEvent(false);
                    handles.Add(manualResetEvent);
                    new Thread(() =>
                    {
                        WalkKey(view, RegistryKey.OpenBaseKey(hive, view));
                        manualResetEvent.Set();
                    }).Start();
                }
            }
            ManualResetEvent.WaitAll(handles.ToArray());
        }

        private static void WalkKey(RegistryView view, RegistryKey key)
        {
            RegistryPath path = new RegistryPath(view, key.Name);
            Write(path);
            string[] valueNames = null;
            try
            {
                valueNames = key.GetValueNames();
            }
            catch { }
            if (valueNames != null)
            {
                foreach (string valueName in valueNames)
                {
                    RegistryValueKind valueKind = RegistryValueKind.Unknown;
                    try
                    {
                        valueKind = key.GetValueKind(valueName);
                    }
                    catch { }
                    object value = key.GetValue(valueName);
                    RegistryPath pathForValue = new RegistryPath(view, key.Name, valueKind, valueName, value);
                    Write(pathForValue);
                }
            }
            string[] subKeyNames = null;
            try
            {
                subKeyNames = key.GetSubKeyNames();
            }
            catch { }
            if (subKeyNames != null)
            {
                foreach (string subKeyName in subKeyNames)
                {
                    try
                    {
                        WalkKey(view, key.OpenSubKey(subKeyName));
                    }
                    catch { }
                }
            }
        }

        private static void Write(RegistryPath path)
        {
            lock (writeLock)
            {
                pathToWrite = path;
                writeReady.Set();
                writeCompleted.WaitOne();
            }
        }

        class RegistryPath
        {
            public RegistryView View;
            public string Path;
            public bool IsKey;
            public RegistryValueKind ValueKind;
            public string ValueName;
            public object Value;
            public int HashValue;

            public RegistryPath(RegistryView view, string path)
            {
                View = view;
                Path = path;
                IsKey = true;
                HashValue = (view.GetHashCode() ^ path.GetHashCode()).GetHashCode();
            }

            public RegistryPath(RegistryView view, string path, RegistryValueKind valueKind, string valueName, object value)
            {
                View = view;
                Path = path;
                IsKey = false;
                ValueKind = valueKind;
                ValueName = valueName;
                Value = value;
                if (value != null)
                {
                    HashValue = (view.GetHashCode() ^ path.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode() ^ value.GetHashCode()).GetHashCode();
                }
                else
                {
                    HashValue = (view.GetHashCode() ^ path.GetHashCode() ^ valueKind.GetHashCode() ^ valueName.GetHashCode()).GetHashCode();
                }
            }
        }
    }
}

这篇关于System.AccessViolationException与SQLite的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆