打开 SQL Server 连接时出现:System.AccessViolationException 尝试读取或写入受保护的内存

4

大家好,

环境:

服务器操作系统:Windows Server 2012R2(64位)

服务器硬件:使用虚拟化软件

应用程序构建在 .net framework 上:4.6.1(编译=Any CPU),WinForms 应用程序

我有一个连接到 SQL server 的应用程序。当应用程序尝试打开 SQL server 连接时,会出现 System.AccessViolationException 异常(以下为堆栈跟踪)。这仅发生在该服务器上。该应用程序在其他服务器/工作站上运行良好。我已经进行了以下测试-请阅读以下内容以获取更多信息(在堆栈跟踪之后)。

异常详细信息:

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


Application: UpdateCenter.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
   at SNINativeMethodWrapper.SNIPacketAllocate(System.Runtime.InteropServices.SafeHandle, IOType, IntPtr ByRef)
   at System.Data.SqlClient.SNIPacket..ctor(System.Runtime.InteropServices.SafeHandle)
   at System.Data.SqlClient.TdsParserStateObject.GetResetWritePacket()
   at System.Data.SqlClient.TdsParserStateObject.WriteSni(Boolean)
   at System.Data.SqlClient.TdsParserStateObject.WritePacket(Byte, Boolean)
   at System.Data.SqlClient.TdsParser.SendPreLoginHandshake(Byte[], Boolean)
   at System.Data.SqlClient.TdsParser.Connect(System.Data.SqlClient.ServerInfo, System.Data.SqlClient.SqlInternalConnectionTds, Boolean, Int64, Boolean, Boolean, Boolean, Boolean, Boolean, System.Data.SqlClient.SqlAuthenticationMethod, Boolean, System.Data.SqlClient.SqlAuthenticationProviderManager)
   at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(System.Data.SqlClient.ServerInfo, System.String, System.Security.SecureString, Boolean, System.Data.ProviderBase.TimeoutTimer, Boolean, Boolean, Boolean)
   at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(System.Data.SqlClient.ServerInfo, System.String, System.Security.SecureString, Boolean, System.Data.SqlClient.SqlConnectionString, System.Data.SqlClient.SqlCredential, System.Data.ProviderBase.TimeoutTimer)
   at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(System.Data.ProviderBase.TimeoutTimer, System.Data.SqlClient.SqlConnectionString, System.Data.SqlClient.SqlCredential, System.String, System.Security.SecureString, Boolean)
   at System.Data.SqlClient.SqlInternalConnectionTds..ctor(System.Data.ProviderBase.DbConnectionPoolIdentity, System.Data.SqlClient.SqlConnectionString, System.Data.SqlClient.SqlCredential, System.Object, System.String, System.Security.SecureString, Boolean, System.Data.SqlClient.SqlConnectionString, System.Data.SqlClient.SessionData, System.Data.ProviderBase.DbConnectionPool, System.String, Boolean, System.Data.SqlClient.SqlAuthenticationProviderManager)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(System.Data.Common.DbConnectionOptions, System.Data.Common.DbConnectionPoolKey, System.Object, System.Data.ProviderBase.DbConnectionPool, System.Data.Common.DbConnection, System.Data.Common.DbConnectionOptions)
   at System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(System.Data.ProviderBase.DbConnectionPool, System.Data.Common.DbConnection, System.Data.Common.DbConnectionOptions, System.Data.Common.DbConnectionPoolKey, System.Data.Common.DbConnectionOptions)
   at System.Data.ProviderBase.DbConnectionPool.CreateObject(System.Data.Common.DbConnection, System.Data.Common.DbConnectionOptions, System.Data.ProviderBase.DbConnectionInternal)
   at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(System.Data.Common.DbConnection, System.Data.Common.DbConnectionOptions, System.Data.ProviderBase.DbConnectionInternal)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(System.Data.Common.DbConnection, UInt32, Boolean, Boolean, System.Data.Common.DbConnectionOptions, System.Data.ProviderBase.DbConnectionInternal ByRef)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(System.Data.Common.DbConnection, System.Threading.Tasks.TaskCompletionSource`1<System.Data.ProviderBase.DbConnectionInternal>, System.Data.Common.DbConnectionOptions, System.Data.ProviderBase.DbConnectionInternal ByRef)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(System.Data.Common.DbConnection, System.Threading.Tasks.TaskCompletionSource`1<System.Data.ProviderBase.DbConnectionInternal>, System.Data.Common.DbConnectionOptions, System.Data.ProviderBase.DbConnectionInternal, System.Data.ProviderBase.DbConnectionInternal ByRef)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(System.Data.Common.DbConnection, System.Data.ProviderBase.DbConnectionFactory, System.Threading.Tasks.TaskCompletionSource`1<System.Data.ProviderBase.DbConnectionInternal>, System.Data.Common.DbConnectionOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(System.Threading.Tasks.TaskCompletionSource`1<System.Data.ProviderBase.DbConnectionInternal>)
   at System.Data.SqlClient.SqlConnection.TryOpen(System.Threading.Tasks.TaskCompletionSource`1<System.Data.ProviderBase.DbConnectionInternal>)
   at System.Data.SqlClient.SqlConnection.Open()
   at PrlSystems.ProductUpdateLibrary.Schema.Drivers.MsSql.SqlServerDataLayerDriver.OpenConnection(System.String)
   at PrlSystems.ProductUpdateLibrary.Schema.DataLayerUpdater.TestConnection(PrlSystems.ProductUpdateLibrary.Schema.DataLayerSettings, System.String ByRef)
   at PrlSystems.UpdateCenter.Forms.Wizard.DatabaseConnectionForm.ctlTestDatabaseConnectionWorker_DoWork(System.Object, System.ComponentModel.DoWorkEventArgs)
   at System.ComponentModel.BackgroundWorker.WorkerThreadStart(System.Object)
   at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr, System.Object[], System.Object, System.Object[] ByRef)
   at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Messaging.IMessageSink)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

引发此异常的代码行是:
connection.Open();

我决定远程连接并调试应用程序,以查看使用的连接字符串(这是完全合法的连接字符串)。接下来,我编写了一个快速而简单的控制台应用程序,使用相同的连接字符串/使用相同的SQL连接对象创建了一个SQL连接,并在同一台服务器上运行它,它可以正常工作。
崩溃应用程序和控制台应用程序之间唯一的区别是:
- 崩溃的应用程序是WinForms应用程序而不是控制台应用程序。 - 崩溃的应用程序在工作线程中执行连接(使用BackgroundWorker)。
我对导致此异常的原因感到无言以对,甚至无法使用我的控制台应用程序重现此异常。任何帮助将不胜感激。
===================== 更新1(测试结果) =====================
  1. I did create another winforms app, and ran the code that does the connection for SQL server and it works fine, ... then I did #2

  2. I edited Program.cs of the app that's crashing and added the following few lines

     static void Main()
     {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);
         // connection that causes access violation exception
         var conn = new SqlConnection();
         conn.ConnectionString = @"Server=.\sqlexpress;Connection Timeout=5;Integrated Security=True";
         conn.Open(); // <= Will get exception after this line executes!
         conn.Close(); 
     }
    

当应用程序运行时,我仍然遇到访问冲突异常。看起来像这个程序被诅咒或列入黑名单!

===================== 更新2(测试结果)=====================

大家好,我已经将整个应用程序精简到只有Program.cs文件,并在Main()函数中只包含连接数据库的几行代码(并引用了几个标准程序集)。即使如此,当应用程序运行时,我仍然看到相同的异常。

然后我将其重新编译为 .NET 2、3.5 版本,它可以工作!但一旦切换到 .NET 4 或更高版本,异常就会回来。您可能认为服务器上安装了错误的软件,但是为什么其他 .NET 4 应用程序运行相同的代码却能正常工作呢?


我查看了那个线程并尝试了Winsock重置,但没有任何不同。请注意,我的情况可能有些不同,因为控制台应用程序运行良好,但执行相同操作的Winform应用程序会崩溃。 - ActiveX
1
你使用的框架版本是哪个?你尝试过其他版本吗? - Charlieface
.net framework 4.6.1,我尝试了4.8版本,但问题依旧。 - ActiveX
2
可能有些困难,但你能否编写一个MRE?让其他人可以运行以重现问题?另外,你是否正在使用连接池?我在堆栈跟踪中看到了它。 - Zer0
如果我在CLR 2.0上运行该应用程序,则它可以正常工作,但是在CLR 4上运行时会崩溃(根据最新测试结果)。 - ActiveX
显示剩余3条评论
1个回答

2

大家好,

我找到了问题的根本原因: 针对 .net 4.5 及以上版本的任何应用程序,在 VS 的 Build/Platform target 下有一个设置:

"Prefer 32 bit"

默认情况下,创建应用程序时会选中此设置。我们的应用程序未选中此设置,导致服务器出现访问冲突异常。勾选此设置解决了问题。

尽管我解决了这个问题……但是如果我需要使用以下目标框架构建应用程序呢:

.net 4.5 > my app >= .net 4.0

由于此设置在 .net 4.5 以下的任何版本中都被禁用,除非我尝试修复服务器并确定软件方面缺少什么或未正确安装,否则我永远无法解决这个问题。这只是因为我们在其他服务器/工作站上运行软件时,它可以正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接