Search code examples
c#.netsql-serverdatabase-connectionmemory-access

Opening SQL Server Connection causes: System.AccessViolationException Attempted to read or write protected memory


All,

Env: Server OS: Windows Server 2012R2 (64bit)

Server hardware: Uses virtualization software

App build on .net framework: 4.6.1 (Compilation=Any CPU), WinForms application

I have an application that connections to SQL server. When the application tries to open SQL server connection I get System.AccessViolationException (stack trace below). This happens only on that server. The application runs fine on other servers/workstations. I've done the following tests - read below (after stack trace for more info).

Exception details:

    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()

The line that's causing this exception is:

connection.Open();

So I decided to attach remotely and debug the application to see what connection string is used (which was perfectly legal connection string). Next, I wrote a quick and dirty console app which creates a SQL connection with the same connection string/using same SQL connection object and ran it on the same server and it works.

The only differences between the console app and the app that's crashing are:

  • The crashing app is a winforms app vs console app
  • The crashing app executes the connection a worker thread (using background worker)

I am lost of words what's causing this exception and I can't even reproduce this with my console app. Any help would be appreciated.

===================== UPDATE 1 (Results of Testing) =====================

  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(); 
     }
    

When the app runs, I still get the access violation exception. This appears like this program is cursed or black listed!

===================== UPDATE 2 (Results of Testing) =====================

All, I have stripped down the entire app to only Program.cs file with just the few lines for connecting to database in Main() function (and referenced only just the few standard assemblies). Still, when the app runs I see the same exception.

Then I re-compiled it to .net 2, 3.5 and it worked! The minute I switch to .net 4 or later the exception is back. You would think something is installed incorrectly on the server but then why the other .net 4 apps work running the exact same code?


Solution

  • All,

    I found the root cause of the problem: For any app targeting .net 4.5 and up there's a setting in VS under Build/Platform target:

    "Prefer 32 bit"

    By default when you create the app, it is checked. Our application had this setting unchecked causing access violation exception on our server. Checking that setting resolved the problem.

    Although, I resolved the issue... it worries me what if I needed to build the app using this target framework: .net 4.5 > my app >= .net 4.0

    Since this setting is disabled for anything below .net 4.5 I could never get around this problem unless I try to fix my server and determine what is missing or is not correctly installed from software perspective. It is this box only because we ran our software on other servers/workstations and it worked fine.